]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
New upstream version 47~beta
authorJeremy Bícha <jeremy.bicha@canonical.com>
Mon, 5 Aug 2024 15:43:49 +0000 (11:43 -0400)
committerJeremy Bícha <jeremy.bicha@canonical.com>
Mon, 5 Aug 2024 15:43:49 +0000 (11:43 -0400)
67 files changed:
1  2 
data/theme/gnome-shell-dark.css
data/theme/gnome-shell-high-contrast.css
data/theme/gnome-shell-light.css
subprojects/jasmine-gjs/.eslintignore
subprojects/jasmine-gjs/.eslintrc.yml
subprojects/jasmine-gjs/.jscsrc
subprojects/jasmine-gjs/.jshintrc
subprojects/jasmine-gjs/.travis.yml
subprojects/jasmine-gjs/COPYING
subprojects/jasmine-gjs/NEWS.md
subprojects/jasmine-gjs/README.md
subprojects/jasmine-gjs/bin/jasmine-runner.in
subprojects/jasmine-gjs/bin/jasmine.in
subprojects/jasmine-gjs/debian/changelog
subprojects/jasmine-gjs/debian/control
subprojects/jasmine-gjs/debian/copyright
subprojects/jasmine-gjs/debian/docs
subprojects/jasmine-gjs/debian/rules
subprojects/jasmine-gjs/debian/source/format
subprojects/jasmine-gjs/jasmine-gjs.spec
subprojects/jasmine-gjs/jasmine.json
subprojects/jasmine-gjs/jasmine.man
subprojects/jasmine-gjs/lib/jasmine.js
subprojects/jasmine-gjs/lib/local-modifications.patch
subprojects/jasmine-gjs/lib/update-jasmine.sh
subprojects/jasmine-gjs/meson.build
subprojects/jasmine-gjs/release-checklist.md
subprojects/jasmine-gjs/src/command.js
subprojects/jasmine-gjs/src/config.js
subprojects/jasmine-gjs/src/consoleReporter.js
subprojects/jasmine-gjs/src/jasmineBoot.js
subprojects/jasmine-gjs/src/junitReporter.js
subprojects/jasmine-gjs/src/options.js
subprojects/jasmine-gjs/src/tapReporter.js
subprojects/jasmine-gjs/src/timer.js
subprojects/jasmine-gjs/src/utils.js
subprojects/jasmine-gjs/src/verboseReporter.js
subprojects/jasmine-gjs/src/xmlWriter.js
subprojects/jasmine-gjs/test/.eslintrc.yml
subprojects/jasmine-gjs/test/commandSpec.js
subprojects/jasmine-gjs/test/configSpec.js
subprojects/jasmine-gjs/test/consoleReporterSpec.js
subprojects/jasmine-gjs/test/defaultReporterSpec.js
subprojects/jasmine-gjs/test/fixtures/include.json
subprojects/jasmine-gjs/test/fixtures/include/module.js
subprojects/jasmine-gjs/test/fixtures/include/spec.js
subprojects/jasmine-gjs/test/fixtures/invalid.json
subprojects/jasmine-gjs/test/fixtures/jasmine.json
subprojects/jasmine-gjs/test/fixtures/notASpec.txt
subprojects/jasmine-gjs/test/fixtures/otherSpec.js
subprojects/jasmine-gjs/test/fixtures/path.json
subprojects/jasmine-gjs/test/fixtures/path1/test.js
subprojects/jasmine-gjs/test/fixtures/path2/test.js
subprojects/jasmine-gjs/test/fixtures/someSpec.js
subprojects/jasmine-gjs/test/fixtures/syntaxErrorSpec.js
subprojects/jasmine-gjs/test/focusedSpecIntegrationTest.js
subprojects/jasmine-gjs/test/importerSpec.js
subprojects/jasmine-gjs/test/jasmineBootSpec.js
subprojects/jasmine-gjs/test/jasmineIntegrationTest.js
subprojects/jasmine-gjs/test/junitReporterSpec.js
subprojects/jasmine-gjs/test/optionsSpec.js
subprojects/jasmine-gjs/test/tapReporterSpec.js
subprojects/jasmine-gjs/test/timerSpec.js
subprojects/jasmine-gjs/test/utils.js
subprojects/jasmine-gjs/test/utilsSpec.js
subprojects/jasmine-gjs/test/verboseReporterSpec.js
subprojects/jasmine-gjs/test/xmlWriterSpec.js

index 780890a3dd3901cebb1b75de5ca3d76b751b0557,0000000000000000000000000000000000000000..6c873d7e8cf575d93310bccb3cf1460dff54cd36
mode 100644,000000..100644
--- /dev/null
@@@ -1,3110 -1,0 +1,3219 @@@
- .unlock-dialog .screenshot-ui-show-pointer-button, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button, #LookingGlassDialog .notebook-tab, #LookingGlassDialog > #Toolbar .lg-toolbar-button, .icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .message .message-header .message-expand-button,
 +/* This stylesheet is generated, DO NOT EDIT */
 +/* Copyright 2009, 2015 Red Hat, Inc.
 + *
 + * Portions adapted from Mx's data/style/default.css
 + *   Copyright 2009 Intel Corporation
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms and conditions of the GNU Lesser General Public License,
 + * version 2.1, as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope it will be useful, but WITHOUT ANY
 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 + * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 + * more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +/* Global Values */
 +stage {
 +  font-size: 1em;
 +  color: #ffffff; }
 +
 +/* Common Stylings */
 +#dash .dash-item-container .show-apps,
 +#dash .dash-item-container .overview-tile,
 +#dash .dash-item-container .grid-search-result {
 +  background: none;
 +  box-shadow: none;
 +  border: none;
 +  border-radius: 0;
 +  padding: 0;
 +  margin: 0; }
 +
 +.app-folder-dialog .overview-tile, .app-folder-dialog .grid-search-result, .app-folder, .overview-tile, .grid-search-result, #dash .dash-item-container .show-apps .overview-icon,
 +#dash .dash-item-container .overview-tile .overview-icon,
 +#dash .dash-item-container .grid-search-result .overview-icon, .list-search-result, .search-provider-icon, .switcher-list .item-box {
 +  border-radius: 16px;
 +  padding: 6px;
 +  spacing: 6px;
 +  text-align: center;
 +  transition-duration: 100ms; }
 +
 +.login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item, .login-dialog-not-listed-button, .unlock-dialog .button,
 +.unlock-dialog .icon-button,
 +.unlock-dialog .message .message-header .message-expand-button,
 +.message .message-header .unlock-dialog .message-expand-button,
 +.unlock-dialog .message .message-header .message-close-button,
 +.message .message-header .unlock-dialog .message-close-button,
-   background-color: #474747; }
++.unlock-dialog .screenshot-ui-show-pointer-button, #LookingGlassDialog .notebook-tab, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button, #LookingGlassDebugFlags .lg-debug-flag-button, #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++#LookingGlassPropertyInspector .lg-obj-inspector-button, #LookingGlassDialog > #Toolbar .lg-toolbar-button, .icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button, .button {
 +  border-radius: 8px;
 +  padding: 3px 24px;
 +  font-weight: bold;
 +  transition: border-width 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); }
 +
 +.icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .screenshot-ui-show-pointer-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button, .button {
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4f; }
++  background-color: st-mix(#ffffff, #353535, 9%); }
 +  .icon-button:focus, .login-dialog-button.cancel-button:focus, .login-dialog-button.switch-user-button:focus, .login-dialog-button.login-dialog-session-list-button:focus, .screenshot-ui-show-pointer-button:focus, .message .message-header .message-expand-button:focus,
 +  .message .message-header .message-close-button:focus, .calendar .calendar-month-header .pager-button:focus, .button:focus {
 +    color: #ffffff;
-       background-color: #505459; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 9%), 5%); }
 +    .icon-button:focus:hover, .login-dialog-button.cancel-button:focus:hover, .login-dialog-button.switch-user-button:focus:hover, .login-dialog-button.login-dialog-session-list-button:focus:hover, .screenshot-ui-show-pointer-button:focus:hover, .message .message-header .message-expand-button:focus:hover,
 +    .message .message-header .message-close-button:focus:hover, .calendar .calendar-month-header .pager-button:focus:hover, .button:focus:hover {
-     background-color: #515151; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 4%), 5%); }
 +  .icon-button:hover, .login-dialog-button.cancel-button:hover, .login-dialog-button.switch-user-button:hover, .login-dialog-button.login-dialog-session-list-button:hover, .screenshot-ui-show-pointer-button:hover, .message .message-header .message-expand-button:hover,
 +  .message .message-header .message-close-button:hover, .calendar .calendar-month-header .pager-button:hover, .button:hover {
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #3f3f3f; }
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 4%); }
 +  .icon-button:insensitive, .login-dialog-button.cancel-button:insensitive, .login-dialog-button.switch-user-button:insensitive, .login-dialog-button.login-dialog-session-list-button:insensitive, .screenshot-ui-show-pointer-button:insensitive, .message .message-header .message-expand-button:insensitive,
 +  .message .message-header .message-close-button:insensitive, .calendar .calendar-month-header .pager-button:insensitive, .button:insensitive {
-     background-color: #5e5e5e; }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #353535, 9%), 3%); }
 +  .icon-button:selected, .login-dialog-button.cancel-button:selected, .login-dialog-button.switch-user-button:selected, .login-dialog-button.login-dialog-session-list-button:selected, .screenshot-ui-show-pointer-button:selected, .message .message-header .message-expand-button:selected,
 +  .message .message-header .message-close-button:selected, .calendar .calendar-month-header .pager-button:selected, .button:selected, .icon-button:active, .login-dialog-button.cancel-button:active, .login-dialog-button.switch-user-button:active, .login-dialog-button.login-dialog-session-list-button:active, .screenshot-ui-show-pointer-button:active, .message .message-header .message-expand-button:active,
 +  .message .message-header .message-close-button:active, .calendar .calendar-month-header .pager-button:active, .button:active {
 +    color: #ffffff;
-       background-color: #686868; }
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 9%); }
 +    .icon-button:selected:hover, .login-dialog-button.cancel-button:selected:hover, .login-dialog-button.switch-user-button:selected:hover, .login-dialog-button.login-dialog-session-list-button:selected:hover, .screenshot-ui-show-pointer-button:selected:hover, .message .message-header .message-expand-button:selected:hover,
 +    .message .message-header .message-close-button:selected:hover, .calendar .calendar-month-header .pager-button:selected:hover, .button:selected:hover, .icon-button:active:hover, .login-dialog-button.cancel-button:active:hover, .login-dialog-button.switch-user-button:active:hover, .login-dialog-button.login-dialog-session-list-button:active:hover, .screenshot-ui-show-pointer-button:active:hover, .message .message-header .message-expand-button:active:hover,
 +    .message .message-header .message-close-button:active:hover, .calendar .calendar-month-header .pager-button:active:hover, .button:active:hover {
-       background-color: #5c6065; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 9%), 4%); }
 +    .icon-button:selected:focus, .login-dialog-button.cancel-button:selected:focus, .login-dialog-button.switch-user-button:selected:focus, .login-dialog-button.login-dialog-session-list-button:selected:focus, .screenshot-ui-show-pointer-button:selected:focus, .message .message-header .message-expand-button:selected:focus,
 +    .message .message-header .message-close-button:selected:focus, .calendar .calendar-month-header .pager-button:selected:focus, .button:selected:focus, .icon-button:active:focus, .login-dialog-button.cancel-button:active:focus, .login-dialog-button.switch-user-button:active:focus, .login-dialog-button.login-dialog-session-list-button:active:focus, .screenshot-ui-show-pointer-button:active:focus, .message .message-header .message-expand-button:active:focus,
 +    .message .message-header .message-close-button:active:focus, .calendar .calendar-month-header .pager-button:active:focus, .button:active:focus {
-     background-color: #5b5b5b; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 9%), 5%); }
 +  .icon-button:checked, .login-dialog-button.cancel-button:checked, .login-dialog-button.switch-user-button:checked, .login-dialog-button.login-dialog-session-list-button:checked, .screenshot-ui-show-pointer-button:checked, .message .message-header .message-expand-button:checked,
 +  .message .message-header .message-close-button:checked, .calendar .calendar-month-header .pager-button:checked, .button:checked {
 +    color: #ffffff;
-       background-color: #666666; }
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 8%); }
 +    .icon-button:checked:hover, .login-dialog-button.cancel-button:checked:hover, .login-dialog-button.switch-user-button:checked:hover, .login-dialog-button.login-dialog-session-list-button:checked:hover, .screenshot-ui-show-pointer-button:checked:hover, .message .message-header .message-expand-button:checked:hover,
 +    .message .message-header .message-close-button:checked:hover, .calendar .calendar-month-header .pager-button:checked:hover, .button:checked:hover {
-       background-color: #727272; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 4%); }
 +    .icon-button:checked:active, .login-dialog-button.cancel-button:checked:active, .login-dialog-button.switch-user-button:checked:active, .login-dialog-button.login-dialog-session-list-button:checked:active, .screenshot-ui-show-pointer-button:checked:active, .message .message-header .message-expand-button:checked:active,
 +    .message .message-header .message-close-button:checked:active, .calendar .calendar-month-header .pager-button:checked:active, .button:checked:active {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(53, 74, 100, 0.2875); }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 9%); }
 +
 +.calendar .calendar-day-heading, .calendar .calendar-day, .calendar .calendar-month-header .calendar-month-label, .icon-button.flat, .flat.login-dialog-button.cancel-button, .flat.login-dialog-button.switch-user-button, .flat.login-dialog-button.login-dialog-session-list-button, .flat.screenshot-ui-show-pointer-button, .message .message-header .flat.message-expand-button,
 +.message .message-header .flat.message-close-button, .calendar .calendar-month-header .pager-button, .button.flat {
 +  color: #ffffff;
 +  background-color: #353535; }
 +  .calendar .calendar-day-heading:focus, .calendar .calendar-day:focus, .calendar .calendar-month-header .calendar-month-label:focus, .icon-button.flat:focus, .flat.login-dialog-button.cancel-button:focus, .flat.login-dialog-button.switch-user-button:focus, .flat.login-dialog-button.login-dialog-session-list-button:focus, .flat.screenshot-ui-show-pointer-button:focus, .message .message-header .flat.message-expand-button:focus,
 +  .message .message-header .flat.message-close-button:focus, .calendar .calendar-month-header .pager-button:focus, .button.flat:focus {
 +    color: #ffffff;
-       background-color: #464a4e; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(53, 53, 53, 0.25), 5%); }
 +    .calendar .calendar-day-heading:focus:hover, .calendar .calendar-day:focus:hover, .calendar .calendar-month-header .calendar-month-label:focus:hover, .icon-button.flat:focus:hover, .flat.login-dialog-button.cancel-button:focus:hover, .flat.login-dialog-button.switch-user-button:focus:hover, .flat.login-dialog-button.login-dialog-session-list-button:focus:hover, .flat.screenshot-ui-show-pointer-button:focus:hover, .message .message-header .flat.message-expand-button:focus:hover,
 +    .message .message-header .flat.message-close-button:focus:hover, .calendar .calendar-month-header .pager-button:focus:hover, .button.flat:focus:hover {
-     background-color: #474747; }
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 7%), 5%); }
 +  .calendar .calendar-day-heading:hover, .calendar .calendar-day:hover, .calendar .calendar-month-header .calendar-month-label:hover, .icon-button.flat:hover, .flat.login-dialog-button.cancel-button:hover, .flat.login-dialog-button.switch-user-button:hover, .flat.login-dialog-button.login-dialog-session-list-button:hover, .flat.screenshot-ui-show-pointer-button:hover, .message .message-header .flat.message-expand-button:hover,
 +  .message .message-header .flat.message-close-button:hover, .calendar .calendar-month-header .pager-button:hover, .button.flat:hover {
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
++    background-color: st-lighten(#353535, 7%); }
 +  .calendar .calendar-day-heading:insensitive, .calendar .calendar-day:insensitive, .calendar .calendar-month-header .calendar-month-label:insensitive, .icon-button.flat:insensitive, .flat.login-dialog-button.cancel-button:insensitive, .flat.login-dialog-button.switch-user-button:insensitive, .flat.login-dialog-button.login-dialog-session-list-button:insensitive, .flat.screenshot-ui-show-pointer-button:insensitive, .message .message-header .flat.message-expand-button:insensitive,
 +  .message .message-header .flat.message-close-button:insensitive, .calendar .calendar-month-header .pager-button:insensitive, .button.flat:insensitive {
-     background-color: #4c4c4c; }
++    color: st-transparentize(#ffffff, 0.5);
 +    background-color: #353535; }
 +  .calendar .calendar-day-heading:selected, .calendar .calendar-day:selected, .calendar .calendar-month-header .calendar-month-label:selected, .icon-button.flat:selected, .flat.login-dialog-button.cancel-button:selected, .flat.login-dialog-button.switch-user-button:selected, .flat.login-dialog-button.login-dialog-session-list-button:selected, .flat.screenshot-ui-show-pointer-button:selected, .message .message-header .flat.message-expand-button:selected,
 +  .message .message-header .flat.message-close-button:selected, .calendar .calendar-month-header .pager-button:selected, .button.flat:selected, .calendar .calendar-day-heading:active, .calendar .calendar-day:active, .calendar .calendar-month-header .calendar-month-label:active, .icon-button.flat:active, .flat.login-dialog-button.cancel-button:active, .flat.login-dialog-button.switch-user-button:active, .flat.login-dialog-button.login-dialog-session-list-button:active, .flat.screenshot-ui-show-pointer-button:active, .message .message-header .flat.message-expand-button:active,
 +  .message .message-header .flat.message-close-button:active, .calendar .calendar-month-header .pager-button:active, .button.flat:active {
 +    color: #ffffff;
-       background-color: #5e5e5e; }
++    background-color: st-lighten(#353535, 9%); }
 +    .calendar .calendar-day-heading:selected:hover, .calendar .calendar-day:selected:hover, .calendar .calendar-month-header .calendar-month-label:selected:hover, .icon-button.flat:selected:hover, .flat.login-dialog-button.cancel-button:selected:hover, .flat.login-dialog-button.switch-user-button:selected:hover, .flat.login-dialog-button.login-dialog-session-list-button:selected:hover, .flat.screenshot-ui-show-pointer-button:selected:hover, .message .message-header .flat.message-expand-button:selected:hover,
 +    .message .message-header .flat.message-close-button:selected:hover, .calendar .calendar-month-header .pager-button:selected:hover, .button.flat:selected:hover, .calendar .calendar-day-heading:active:hover, .calendar .calendar-day:active:hover, .calendar .calendar-month-header .calendar-month-label:active:hover, .icon-button.flat:active:hover, .flat.login-dialog-button.cancel-button:active:hover, .flat.login-dialog-button.switch-user-button:active:hover, .flat.login-dialog-button.login-dialog-session-list-button:active:hover, .flat.screenshot-ui-show-pointer-button:active:hover, .message .message-header .flat.message-expand-button:active:hover,
 +    .message .message-header .flat.message-close-button:active:hover, .calendar .calendar-month-header .pager-button:active:hover, .button.flat:active:hover {
-       background-color: #4b4f53; }
++      background-color: st-lighten(st-lighten(#353535, 9%), 7%); }
 +    .calendar .calendar-day-heading:selected:focus, .calendar .calendar-day:selected:focus, .calendar .calendar-month-header .calendar-month-label:selected:focus, .icon-button.flat:selected:focus, .flat.login-dialog-button.cancel-button:selected:focus, .flat.login-dialog-button.switch-user-button:selected:focus, .flat.login-dialog-button.login-dialog-session-list-button:selected:focus, .flat.screenshot-ui-show-pointer-button:selected:focus, .message .message-header .flat.message-expand-button:selected:focus,
 +    .message .message-header .flat.message-close-button:selected:focus, .calendar .calendar-month-header .pager-button:selected:focus, .button.flat:selected:focus, .calendar .calendar-day-heading:active:focus, .calendar .calendar-day:active:focus, .calendar .calendar-month-header .calendar-month-label:active:focus, .icon-button.flat:active:focus, .flat.login-dialog-button.cancel-button:active:focus, .flat.login-dialog-button.switch-user-button:active:focus, .flat.login-dialog-button.login-dialog-session-list-button:active:focus, .flat.screenshot-ui-show-pointer-button:active:focus, .message .message-header .flat.message-expand-button:active:focus,
 +    .message .message-header .flat.message-close-button:active:focus, .calendar .calendar-month-header .pager-button:active:focus, .button.flat:active:focus {
-     background-color: #494949; }
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 9%), 5%); }
 +  .calendar .calendar-day-heading:checked, .calendar .calendar-day:checked, .calendar .calendar-month-header .calendar-month-label:checked, .icon-button.flat:checked, .flat.login-dialog-button.cancel-button:checked, .flat.login-dialog-button.switch-user-button:checked, .flat.login-dialog-button.login-dialog-session-list-button:checked, .flat.screenshot-ui-show-pointer-button:checked, .message .message-header .flat.message-expand-button:checked,
 +  .message .message-header .flat.message-close-button:checked, .calendar .calendar-month-header .pager-button:checked, .button.flat:checked {
 +    color: #ffffff;
-       background-color: #5b5b5b; }
++    background-color: st-lighten(#353535, 8%); }
 +    .calendar .calendar-day-heading:checked:hover, .calendar .calendar-day:checked:hover, .calendar .calendar-month-header .calendar-month-label:checked:hover, .icon-button.flat:checked:hover, .flat.login-dialog-button.cancel-button:checked:hover, .flat.login-dialog-button.switch-user-button:checked:hover, .flat.login-dialog-button.login-dialog-session-list-button:checked:hover, .flat.screenshot-ui-show-pointer-button:checked:hover, .message .message-header .flat.message-expand-button:checked:hover,
 +    .message .message-header .flat.message-close-button:checked:hover, .calendar .calendar-month-header .pager-button:checked:hover, .button.flat:checked:hover {
-       background-color: #606060; }
++      background-color: st-lighten(st-lighten(#353535, 8%), 7%); }
 +    .calendar .calendar-day-heading:checked:active, .calendar .calendar-day:checked:active, .calendar .calendar-month-header .calendar-month-label:checked:active, .icon-button.flat:checked:active, .flat.login-dialog-button.cancel-button:checked:active, .flat.login-dialog-button.switch-user-button:checked:active, .flat.login-dialog-button.login-dialog-session-list-button:checked:active, .flat.screenshot-ui-show-pointer-button:checked:active, .message .message-header .flat.message-expand-button:checked:active,
 +    .message .message-header .flat.message-close-button:checked:active, .calendar .calendar-month-header .pager-button:checked:active, .button.flat:checked:active {
-   color: #ffffff;
-   background-color: #3584e4; }
++      background-color: st-lighten(st-lighten(#353535, 8%), 9%); }
 +
 +.keyboard-brightness-level .button:checked, .quick-menu-toggle .quick-toggle-arrow:checked, .quick-toggle:checked, .calendar .calendar-day.calendar-today, .icon-button.default, .default.login-dialog-button.cancel-button, .default.login-dialog-button.switch-user-button, .default.login-dialog-button.login-dialog-session-list-button, .default.screenshot-ui-show-pointer-button, .message .message-header .default.message-expand-button,
 +.message .message-header .default.message-close-button, .calendar .calendar-month-header .default.pager-button, .button.default {
-     color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     box-shadow: inset 0 0 0 2px #78aded !important;
-     background-color: #3584e4; }
++  color: -st-accent-fg-color;
++  background-color: -st-accent-color; }
 +  .keyboard-brightness-level .button:focus:checked, .quick-menu-toggle .quick-toggle-arrow:focus:checked, .quick-toggle:focus:checked, .calendar .calendar-day.calendar-today:focus, .icon-button.default:focus, .default.login-dialog-button.cancel-button:focus, .default.login-dialog-button.switch-user-button:focus, .default.login-dialog-button.login-dialog-session-list-button:focus, .default.screenshot-ui-show-pointer-button:focus, .message .message-header .default.message-expand-button:focus,
 +  .message .message-header .default.message-close-button:focus, .calendar .calendar-month-header .default.pager-button:focus, .button.default:focus {
-       background-color: #468ee6; }
++    color: -st-accent-fg-color;
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    box-shadow: inset 0 0 0 2px st-lighten(-st-accent-color, 15%) !important;
++    background-color: st-mix(-st-accent-color, -st-accent-color, 5%); }
 +    .keyboard-brightness-level .button:focus:hover:checked, .quick-menu-toggle .quick-toggle-arrow:focus:hover:checked, .quick-toggle:focus:hover:checked, .calendar .calendar-day.calendar-today:focus:hover, .icon-button.default:focus:hover, .default.login-dialog-button.cancel-button:focus:hover, .default.login-dialog-button.switch-user-button:focus:hover, .default.login-dialog-button.login-dialog-session-list-button:focus:hover, .default.screenshot-ui-show-pointer-button:focus:hover, .message .message-header .default.message-expand-button:focus:hover,
 +    .message .message-header .default.message-close-button:focus:hover, .calendar .calendar-month-header .default.pager-button:focus:hover, .button.default:focus:hover {
-     color: #ffffff;
-     background-color: #478fe6; }
++      background-color: st-mix(-st-accent-color, st-lighten(-st-accent-color, 4%), 5%); }
 +  .keyboard-brightness-level .button:hover:checked, .quick-menu-toggle .quick-toggle-arrow:hover:checked, .quick-toggle:hover:checked, .calendar .calendar-day.calendar-today:hover, .icon-button.default:hover, .default.login-dialog-button.cancel-button:hover, .default.login-dialog-button.switch-user-button:hover, .default.login-dialog-button.login-dialog-session-list-button:hover, .default.screenshot-ui-show-pointer-button:hover, .message .message-header .default.message-expand-button:hover,
 +  .message .message-header .default.message-close-button:hover, .calendar .calendar-month-header .default.pager-button:hover, .button.default:hover {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #287ce2; }
++    color: -st-accent-fg-color;
++    background-color: st-lighten(-st-accent-color, 4%); }
 +  .keyboard-brightness-level .button:insensitive:checked, .quick-menu-toggle .quick-toggle-arrow:insensitive:checked, .quick-toggle:insensitive:checked, .calendar .calendar-day.calendar-today:insensitive, .icon-button.default:insensitive, .default.login-dialog-button.cancel-button:insensitive, .default.login-dialog-button.switch-user-button:insensitive, .default.login-dialog-button.login-dialog-session-list-button:insensitive, .default.screenshot-ui-show-pointer-button:insensitive, .message .message-header .default.message-expand-button:insensitive,
 +  .message .message-header .default.message-close-button:insensitive, .calendar .calendar-month-header .default.pager-button:insensitive, .button.default:insensitive {
-     color: #ffffff;
-     background-color: #5d9de9; }
++    color: st-transparentize(-st-accent-fg-color, 0.5);
++    background-color: st-darken(-st-accent-color, 3%); }
 +  .keyboard-brightness-level .button:active:checked, .quick-menu-toggle .quick-toggle-arrow:active:checked, .quick-toggle:active:checked, .calendar .calendar-day.calendar-today:active, .icon-button.default:active, .default.login-dialog-button.cancel-button:active, .default.login-dialog-button.switch-user-button:active, .default.login-dialog-button.login-dialog-session-list-button:active, .default.screenshot-ui-show-pointer-button:active, .message .message-header .default.message-expand-button:active,
 +  .message .message-header .default.message-close-button:active, .calendar .calendar-month-header .default.pager-button:active, .button.default:active {
-       background-color: #6fa8ec; }
++    color: -st-accent-fg-color;
++    background-color: st-lighten(-st-accent-color, 9%); }
 +    .keyboard-brightness-level .button:active:hover:checked, .quick-menu-toggle .quick-toggle-arrow:active:hover:checked, .quick-toggle:active:hover:checked, .calendar .calendar-day.calendar-today:active:hover, .icon-button.default:active:hover, .default.login-dialog-button.cancel-button:active:hover, .default.login-dialog-button.switch-user-button:active:hover, .default.login-dialog-button.login-dialog-session-list-button:active:hover, .default.screenshot-ui-show-pointer-button:active:hover, .message .message-header .default.message-expand-button:active:hover,
 +    .message .message-header .default.message-close-button:active:hover, .calendar .calendar-month-header .default.pager-button:active:hover, .button.default:active:hover {
-       background-color: #5b9be9; }
++      background-color: st-lighten(st-lighten(-st-accent-color, 9%), 4%); }
 +    .keyboard-brightness-level .button:active:focus:checked, .quick-menu-toggle .quick-toggle-arrow:active:focus:checked, .quick-toggle:active:focus:checked, .calendar .calendar-day.calendar-today:active:focus, .icon-button.default:active:focus, .default.login-dialog-button.cancel-button:active:focus, .default.login-dialog-button.switch-user-button:active:focus, .default.login-dialog-button.login-dialog-session-list-button:active:focus, .default.screenshot-ui-show-pointer-button:active:focus, .message .message-header .default.message-expand-button:active:focus,
 +    .message .message-header .default.message-close-button:active:focus, .calendar .calendar-month-header .default.pager-button:active:focus, .button.default:active:focus {
- .calendar, .datemenu-today-button, .lg-extension, .quick-toggle-menu, .message, .events-button,
++      background-color: st-mix(-st-accent-color, st-lighten(-st-accent-color, 9%), 5%); }
 +
 +.popup-sub-menu .popup-menu-item, .popup-menu-item {
 +  font-weight: normal;
 +  spacing: 6px;
 +  transition-duration: 100ms;
 +  padding: 9px 12px; }
 +
- .lg-extension, .quick-toggle-menu, .message, .events-button,
++#LookingGlassExtensions .lg-extension, #LookingGlassWindows .lg-window, .calendar, .datemenu-today-button, .quick-toggle-menu, .message, .events-button,
 +.world-clocks-button,
 +.weather-button {
 +  border-radius: 12px;
 +  padding: 0.818em;
 +  margin: 4px;
 +  background-color: #474747;
 +  box-shadow: 0 1px 2px 0 transparent;
 +  border: 1px solid transparent; }
 +
-   .lg-extension:hover, .quick-toggle-menu:hover, .message:hover, .events-button:hover,
++.quick-toggle-menu, .message, .events-button,
 +.world-clocks-button,
 +.weather-button {
 +  color: #ffffff;
 +  background-color: #474747; }
-     background-color: #515151; }
-   .lg-extension:active, .quick-toggle-menu:active, .message:active, .events-button:active,
++  .quick-toggle-menu:hover, .message:hover, .events-button:hover,
 +  .world-clocks-button:hover,
 +  .weather-button:hover {
 +    color: #ffffff;
-     background-color: #5e5e5e; }
-     .lg-extension:active:hover, .quick-toggle-menu:active:hover, .message:active:hover, .events-button:active:hover,
++    background-color: st-lighten(#474747, 4%); }
++  .quick-toggle-menu:active, .message:active, .events-button:active,
 +  .world-clocks-button:active,
 +  .weather-button:active {
 +    color: #ffffff;
-       background-color: #686868; }
-     .lg-extension:active:focus, .quick-toggle-menu:active:focus, .message:active:focus, .events-button:active:focus,
++    background-color: st-lighten(#474747, 9%); }
++    .quick-toggle-menu:active:hover, .message:active:hover, .events-button:active:hover,
 +    .world-clocks-button:active:hover,
 +    .weather-button:active:hover {
-       background-color: #5c5f64; }
-   .lg-extension:focus, .quick-toggle-menu:focus, .message:focus, .events-button:focus,
++      background-color: st-lighten(st-lighten(#474747, 9%), 4%); }
++    .quick-toggle-menu:active:focus, .message:active:focus, .events-button:active:focus,
 +    .world-clocks-button:active:focus,
 +    .weather-button:active:focus {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4e; }
-     .lg-extension:focus:hover, .quick-toggle-menu:focus:hover, .message:focus:hover, .events-button:focus:hover,
++      background-color: st-mix(-st-accent-color, st-lighten(#474747, 9%), 5%); }
++  .quick-toggle-menu:focus, .message:focus, .events-button:focus,
 +  .world-clocks-button:focus,
 +  .weather-button:focus {
 +    color: #ffffff;
-       background-color: #4f5358; }
-   .lg-extension:insensitive, .quick-toggle-menu:insensitive, .message:insensitive, .events-button:insensitive,
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #474747, 5%); }
++    .quick-toggle-menu:focus:hover, .message:focus:hover, .events-button:focus:hover,
 +    .world-clocks-button:focus:hover,
 +    .weather-button:focus:hover {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #3f3f3f; }
++      background-color: st-mix(-st-accent-color, st-lighten(#474747, 4%), 5%); }
++  .quick-toggle-menu:insensitive, .message:insensitive, .events-button:insensitive,
 +  .world-clocks-button:insensitive,
 +  .weather-button:insensitive {
-     background-color: #474747; }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(#474747, 3%); }
 +
 +.calendar, .datemenu-today-button {
 +  border: 1px solid transparent !important;
 +  background-color: transparent;
 +  border-color: transparent;
 +  box-shadow: none; }
 +  .calendar:insensitive, .datemenu-today-button:insensitive {
 +    background-color: transparent !important; }
 +  .calendar:hover, .datemenu-today-button:hover {
 +    color: #ffffff;
-     background-color: #4c4c4c; }
++    background-color: st-lighten(#353535, 7%); }
 +  .calendar:active, .datemenu-today-button:active {
 +    color: #ffffff;
-       background-color: #5e5e5e; }
++    background-color: st-lighten(#353535, 9%); }
 +    .calendar:active:hover, .datemenu-today-button:active:hover {
-       background-color: #4b4f53; }
++      background-color: st-lighten(st-lighten(#353535, 9%), 7%); }
 +    .calendar:active:focus, .datemenu-today-button:active:focus {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4e; }
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 9%), 5%); }
 +  .calendar:focus, .datemenu-today-button:focus {
 +    color: #ffffff;
-       background-color: #4f5358; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #474747, 5%); }
 +    .calendar:focus:hover, .datemenu-today-button:focus:hover {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #3f3f3f; }
++      background-color: st-mix(-st-accent-color, st-lighten(#474747, 4%), 5%); }
 +  .calendar:insensitive, .datemenu-today-button:insensitive {
-   selection-background-color: #3584e4;
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(#474747, 3%); }
 +
 +.unlock-dialog .login-dialog-prompt-entry, .login-dialog .login-dialog-prompt-entry, .app-folder-dialog .folder-name-container .folder-name-entry, .search-entry, .lg-dialog StEntry, StEntry {
 +  border-radius: 8px;
 +  padding: 9px 9px;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4f;
++  selection-background-color: st-transparentize(-st-accent-color, 0.7);
 +  selected-color: #ffffff; }
 +
 +StEntry {
 +  background-color: #474747;
 +  color: rgba(255, 255, 255, 0.7); }
 +  StEntry:hover {
 +    background-color: #515151;
 +    color: #ffffff; }
 +  StEntry:focus {
- .modal-dialog .modal-dialog-linked-button, .notification-button {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #474747, 5%);
 +    color: #ffffff; }
 +  StEntry:insensitive {
 +    background-color: #3f3f3f;
 +    color: rgba(255, 255, 255, 0.5); }
 +  StEntry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
-   font-weight: bold !important;
++.notification-button, .message .message-header .message-expand-button,
++.message .message-header .message-close-button {
++  font-weight: bold;
++  padding: 6px 12px;
++  border-radius: 8px;
++  color: #ffffff;
++  background-color: rgba(255, 255, 255, 0.15); }
++  .notification-button:focus, .message .message-header .message-expand-button:focus,
++  .message .message-header .message-close-button:focus {
++    color: #ffffff;
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.15), 5%); }
++    .notification-button:focus:hover, .message .message-header .message-expand-button:focus:hover,
++    .message .message-header .message-close-button:focus:hover {
++      background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.3), 5%); }
++  .notification-button:hover, .message .message-header .message-expand-button:hover,
++  .message .message-header .message-close-button:hover {
++    color: #ffffff;
++    background-color: rgba(255, 255, 255, 0.3); }
++  .notification-button:active, .message .message-header .message-expand-button:active,
++  .message .message-header .message-close-button:active {
++    color: #ffffff;
++    background-color: rgba(255, 255, 255, 0.2); }
++    .notification-button:active:hover, .message .message-header .message-expand-button:active:hover,
++    .message .message-header .message-close-button:active:hover {
++      background-color: rgba(255, 255, 255, 0.2); }
++    .notification-button:active:focus, .message .message-header .message-expand-button:active:focus,
++    .message .message-header .message-close-button:active:focus {
++      background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.2), 5%); }
++  .notification-button:checked, .message .message-header .message-expand-button:checked,
++  .message .message-header .message-close-button:checked {
++    color: #ffffff;
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 8%); }
++    .notification-button:checked:hover, .message .message-header .message-expand-button:checked:hover,
++    .message .message-header .message-close-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 4%); }
++    .notification-button:checked:active, .message .message-header .message-expand-button:checked:active,
++    .message .message-header .message-close-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 9%); }
++  .notification-button:insensitive, .message .message-header .message-expand-button:insensitive,
++  .message .message-header .message-close-button:insensitive {
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: rgba(255, 255, 255, 0.1); }
++
++.modal-dialog .modal-dialog-linked-button {
++  font-weight: bold;
 +  padding: 12px;
-   .modal-dialog .modal-dialog-linked-button:ltr, .notification-button:ltr {
-     margin-right: 1px; }
-   .modal-dialog .modal-dialog-linked-button:rtl, .notification-button:rtl {
-     margin-left: 1px; }
-   .modal-dialog .modal-dialog-linked-button:focus, .notification-button:focus {
++  border-radius: 12px;
 +  color: #ffffff;
 +  background-color: rgba(255, 255, 255, 0.1); }
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(154, 194, 242, 0.145); }
-     .modal-dialog .modal-dialog-linked-button:focus:hover, .notification-button:focus:hover {
-       background-color: rgba(168, 202, 243, 0.1735); }
-   .modal-dialog .modal-dialog-linked-button:hover, .notification-button:hover {
++  .modal-dialog .modal-dialog-linked-button:focus {
 +    color: #ffffff;
-   .modal-dialog .modal-dialog-linked-button:active, .notification-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.1), 5%); }
++    .modal-dialog .modal-dialog-linked-button:focus:hover {
++      background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.13), 5%); }
++  .modal-dialog .modal-dialog-linked-button:hover {
 +    color: #ffffff;
 +    background-color: rgba(255, 255, 255, 0.13); }
-     .modal-dialog .modal-dialog-linked-button:active:hover, .notification-button:active:hover {
++  .modal-dialog .modal-dialog-linked-button:active {
 +    color: #ffffff;
 +    background-color: rgba(255, 255, 255, 0.16); }
-     .modal-dialog .modal-dialog-linked-button:active:focus, .notification-button:active:focus {
-       background-color: rgba(179, 209, 245, 0.202); }
-   .modal-dialog .modal-dialog-linked-button:checked, .notification-button:checked {
++    .modal-dialog .modal-dialog-linked-button:active:hover {
 +      background-color: rgba(255, 255, 255, 0.19); }
-     background-color: #5b5b5b; }
-     .modal-dialog .modal-dialog-linked-button:checked:hover, .notification-button:checked:hover {
-       background-color: #666666; }
-     .modal-dialog .modal-dialog-linked-button:checked:active, .notification-button:checked:active {
-       background-color: #727272; }
-   .modal-dialog .modal-dialog-linked-button:insensitive, .notification-button:insensitive {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #3f3f3f; }
-   .modal-dialog .modal-dialog-linked-button:first-child:ltr, .notification-button:first-child:ltr {
-     border-radius: 0 0 0 15px; }
-   .modal-dialog .modal-dialog-linked-button:last-child:ltr, .notification-button:last-child:ltr {
-     border-radius: 0 0 15px;
-     margin-right: 0 !important; }
-   .modal-dialog .modal-dialog-linked-button:first-child:rtl, .notification-button:first-child:rtl {
-     border-radius: 0 0 15px; }
-   .modal-dialog .modal-dialog-linked-button:last-child:rtl, .notification-button:last-child:rtl {
-     border-radius: 0 0 0 15px;
-     margin-left: 0 !important; }
-   .modal-dialog .modal-dialog-linked-button:first-child:last-child, .notification-button:first-child:last-child {
-     border-radius: 0 0 15px 15px;
-     margin-left: 0 !important;
-     margin-right: 0 !important; }
++    .modal-dialog .modal-dialog-linked-button:active:focus {
++      background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.16), 5%); }
++  .modal-dialog .modal-dialog-linked-button:checked {
 +    color: #ffffff;
- .login-dialog .user-widget.vertical .user-widget-label,
- .unlock-dialog .user-widget.vertical .user-widget-label, .unlock-dialog-clock .unlock-dialog-clock-date, .app-folder-dialog .folder-name-container .folder-name-label, .app-folder-dialog .folder-name-container .folder-name-entry, .search-statustext {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 8%); }
++    .modal-dialog .modal-dialog-linked-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 4%); }
++    .modal-dialog .modal-dialog-linked-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 9%); }
++  .modal-dialog .modal-dialog-linked-button:insensitive {
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #353535, 9%), 3%); }
 +
 +.dash-label, .window-caption, .screenshot-ui-tooltip {
 +  background-color: rgba(0, 0, 0, 0.9);
 +  border: 1px solid rgba(255, 255, 255, 0.1);
 +  color: #ffffff;
 +  border-radius: 999px;
 +  padding: 6px 12px;
 +  text-align: center; }
 +
 +/* General Typography */
- .conflicting-session-dialog-content .conflicting-session-dialog-title, .lg-debug-flags-header, .message-dialog-content .message-dialog-title, .message-list .message-list-placeholder, .datemenu-today-button .date-label {
++.unlock-dialog-clock .unlock-dialog-clock-date, .app-folder-dialog .folder-name-container .folder-name-label, .app-folder-dialog .folder-name-container .folder-name-entry, .search-statustext {
 +  font-weight: 800;
 +  font-size: 1.818em; }
 +
- .login-dialog-auth-list-label, .word-suggestions, .bt-menu-placeholder.popup-menu-item, .message-dialog-content .message-dialog-title.lightweight, .headline {
++.conflicting-session-dialog-content .conflicting-session-dialog-title, .message-dialog-content .message-dialog-title, .message-list .message-list-placeholder, .datemenu-today-button .date-label {
 +  font-weight: 800;
 +  font-size: 1.364em; }
 +
 +.login-dialog .user-widget.horizontal .user-widget-label,
 +.unlock-dialog .user-widget.horizontal .user-widget-label, .quick-toggle-menu .header .title {
 +  font-weight: 700;
 +  font-size: 1.364em; }
 +
- .login-dialog-not-listed-label, .lg-extension-name, .background-app-item .title, .osd-window, .dialog-list .dialog-list-title, .message-list-controls, .weather-button .weather-box .weather-header-box .weather-header, .world-clocks-button .world-clocks-header, .events-button .events-box .events-list .event-box .event-summary, .events-button .events-box .events-title, .calendar .calendar-month-header .calendar-month-label {
++.login-dialog-auth-list-label, #LookingGlassDebugFlags .lg-debug-flags-header, #LookingGlassExtensions .lg-extensions-none, .word-suggestions, .bt-menu-placeholder.popup-menu-item, .message-dialog-content .message-dialog-title.lightweight, .headline {
 +  font-weight: 700;
 +  font-size: 1.182em; }
 +
- #EvalBox {
++.login-dialog-not-listed-label, #LookingGlassExtensions .lg-extension .lg-extension-name, #LookingGlassWindows .lg-window .lg-window-name, #LookingGlassPropertyInspector .lg-obj-inspector-title, .background-app-item .title, .osd-window, .dialog-list .dialog-list-title, .message-list-controls, .weather-button .weather-box .weather-header-box .weather-header, .world-clocks-button .world-clocks-header, .events-button .events-box .events-list .event-box .event-summary, .events-button .events-box .events-title, .calendar .calendar-month-header .calendar-month-label {
 +  font-weight: 700;
 +  font-size: 1em; }
 +
 +.quick-toggle-menu .header .subtitle, .app-menu .popup-inactive-menu-item:first-child > StLabel {
 +  font-weight: 700;
 +  font-size: 0.818em; }
 +
 +.lg-completions-text, .caps-lock-warning-label, .background-app-item .subtitle, .quick-toggle StBoxLayout > .quick-toggle-subtitle, .screenshot-ui-type-button .icon-label-button-container, .prompt-dialog-error-label,
 +.prompt-dialog-info-label,
 +.prompt-dialog-null-label, .run-dialog .run-dialog-description, .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-description, .message .message-header .message-header-content .event-time, .world-clocks-button .world-clocks-grid .world-clocks-timezone, .events-button .events-box .events-list .event-box .event-time {
 +  font-weight: 400;
 +  font-size: 0.818em; }
 +
 +.weather-button .weather-box .weather-grid .weather-forecast-time, .calendar .calendar-week-number, .calendar .calendar-day-heading, .calendar .calendar-day {
 +  font-weight: 400;
 +  font-size: 0.818em; }
 +
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4f;
++#LookingGlassDebugFlags .lg-debug-flag-button StLabel, #LookingGlassEvaluator .evaluator-results, .lg-dialog .actor-link {
 +  font-family: monospace; }
 +
 +.unlock-dialog-clock .unlock-dialog-clock-time, #panel, .weather-button .weather-box .weather-grid .weather-forecast-temp, .world-clocks-button .world-clocks-grid .world-clocks-timezone, .world-clocks-button .world-clocks-grid .world-clocks-time, .events-button .events-box .events-list .event-box .event-time, .calendar .calendar-day-heading, .calendar .calendar-day {
 +  font-feature-settings: "tnum"; }
 +
 +/* OSD Elements */
 +#LookingGlassDialog, .screenshot-ui-panel, .workspace-switcher, .switcher-list, .resize-popup, .osd-window {
 +  color: #ffffff;
 +  background-color: #353535;
 +  border: 1px solid rgba(255, 255, 255, 0.02);
 +  border-radius: 999px;
 +  padding: 12px; }
 +
 +.lg-dialog StEntry {
 +  background-color: #474747;
 +  color: rgba(255, 255, 255, 0.7); }
 +  .lg-dialog StEntry:hover {
 +    background-color: #515151;
 +    color: #ffffff; }
 +  .lg-dialog StEntry:focus {
- #LookingGlassDialog .notebook-tab, #LookingGlassDialog > #Toolbar .lg-toolbar-button {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #474747, 5%);
 +    color: #ffffff; }
 +  .lg-dialog StEntry:insensitive {
 +    background-color: #3f3f3f;
 +    color: rgba(255, 255, 255, 0.5); }
 +  .lg-dialog StEntry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
-   background-color: #474747; }
-   #LookingGlassDialog .notebook-tab:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus {
++#LookingGlassDebugFlags .lg-debug-flag-button, #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++#LookingGlassPropertyInspector .lg-obj-inspector-button, #LookingGlassDialog > #Toolbar .lg-toolbar-button {
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4f; }
-     #LookingGlassDialog .notebook-tab:focus:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus:hover {
-       background-color: #505459; }
-   #LookingGlassDialog .notebook-tab:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:hover {
++  background-color: st-mix(#ffffff, #353535, 9%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:focus, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:focus,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus {
 +    color: #ffffff;
-     background-color: #515151; }
-   #LookingGlassDialog .notebook-tab:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 9%), 5%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:focus:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:focus:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:focus:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 4%), 5%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:hover,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:hover {
 +    color: #ffffff;
-     background-color: #5e5e5e; }
-     #LookingGlassDialog .notebook-tab:active:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:hover {
-       background-color: #686868; }
-     #LookingGlassDialog .notebook-tab:active:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:focus {
-       background-color: #5c6065; }
-   #LookingGlassDialog .notebook-tab:checked, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 4%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:active, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active {
 +    color: #ffffff;
-     background-color: #5b5b5b; }
-     #LookingGlassDialog .notebook-tab:checked:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:hover {
-       background-color: #666666; }
-     #LookingGlassDialog .notebook-tab:checked:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:active {
-       background-color: #727272; }
-   #LookingGlassDialog .notebook-tab:insensitive, #LookingGlassDialog > #Toolbar .lg-toolbar-button:insensitive {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #3f3f3f; }
- 
- .screenshot-ui-show-pointer-button, .screenshot-ui-type-button {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 9%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:active:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:active:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 9%), 4%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:active:focus, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active:focus,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:active:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 9%), 5%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:checked, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:checked, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked {
 +    color: #ffffff;
-   .screenshot-ui-show-pointer-button:focus, .screenshot-ui-type-button:focus {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 8%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:checked:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:checked:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 4%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:checked:active, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked:active,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:checked:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 8%), 9%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:insensitive, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:insensitive,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:insensitive, #LookingGlassDialog > #Toolbar .lg-toolbar-button:insensitive {
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #353535, 9%), 3%); }
++
++#LookingGlassDialog .notebook-tab, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button {
 +  color: #ffffff;
 +  background-color: #353535; }
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(53, 74, 100, 0.2875); }
-     .screenshot-ui-show-pointer-button:focus:hover, .screenshot-ui-type-button:focus:hover {
-       background-color: #464a4e; }
-   .screenshot-ui-show-pointer-button:hover, .screenshot-ui-type-button:hover {
++  #LookingGlassDialog .notebook-tab:focus, .screenshot-ui-show-pointer-button:focus, .screenshot-ui-type-button:focus {
 +    color: #ffffff;
-     background-color: #474747; }
-   .screenshot-ui-show-pointer-button:active, .screenshot-ui-type-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(53, 53, 53, 0.25), 5%); }
++    #LookingGlassDialog .notebook-tab:focus:hover, .screenshot-ui-show-pointer-button:focus:hover, .screenshot-ui-type-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 7%), 5%); }
++  #LookingGlassDialog .notebook-tab:hover, .screenshot-ui-show-pointer-button:hover, .screenshot-ui-type-button:hover {
 +    color: #ffffff;
-     background-color: #4c4c4c; }
-     .screenshot-ui-show-pointer-button:active:hover, .screenshot-ui-type-button:active:hover {
-       background-color: #5e5e5e; }
-     .screenshot-ui-show-pointer-button:active:focus, .screenshot-ui-type-button:active:focus {
-       background-color: #4b4f53; }
-   .screenshot-ui-show-pointer-button:checked, .screenshot-ui-type-button:checked {
++    background-color: st-lighten(#353535, 7%); }
++  #LookingGlassDialog .notebook-tab:active, .screenshot-ui-show-pointer-button:active, .screenshot-ui-type-button:active {
 +    color: #ffffff;
-     background-color: #494949; }
-     .screenshot-ui-show-pointer-button:checked:hover, .screenshot-ui-type-button:checked:hover {
-       background-color: #5b5b5b; }
-     .screenshot-ui-show-pointer-button:checked:active, .screenshot-ui-type-button:checked:active {
-       background-color: #606060; }
-   .screenshot-ui-show-pointer-button:insensitive, .screenshot-ui-type-button:insensitive {
-     color: rgba(255, 255, 255, 0.5);
++    background-color: st-lighten(#353535, 9%); }
++    #LookingGlassDialog .notebook-tab:active:hover, .screenshot-ui-show-pointer-button:active:hover, .screenshot-ui-type-button:active:hover {
++      background-color: st-lighten(st-lighten(#353535, 9%), 7%); }
++    #LookingGlassDialog .notebook-tab:active:focus, .screenshot-ui-show-pointer-button:active:focus, .screenshot-ui-type-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 9%), 5%); }
++  #LookingGlassDialog .notebook-tab:checked, .screenshot-ui-show-pointer-button:checked, .screenshot-ui-type-button:checked {
 +    color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #45494e;
++    background-color: st-lighten(#353535, 8%); }
++    #LookingGlassDialog .notebook-tab:checked:hover, .screenshot-ui-show-pointer-button:checked:hover, .screenshot-ui-type-button:checked:hover {
++      background-color: st-lighten(st-lighten(#353535, 8%), 7%); }
++    #LookingGlassDialog .notebook-tab:checked:active, .screenshot-ui-show-pointer-button:checked:active, .screenshot-ui-type-button:checked:active {
++      background-color: st-lighten(st-lighten(#353535, 8%), 9%); }
++  #LookingGlassDialog .notebook-tab:insensitive, .screenshot-ui-show-pointer-button:insensitive, .screenshot-ui-type-button:insensitive {
++    color: st-transparentize(#ffffff, 0.5);
 +    background-color: #353535; }
 +
 +/* System Elements */
 +.login-dialog .login-dialog-prompt-entry, .app-folder-dialog .folder-name-container .folder-name-entry, .search-entry {
 +  background-color: #464646;
 +  color: rgba(245, 245, 245, 0.7); }
 +  .login-dialog .login-dialog-prompt-entry:hover, .app-folder-dialog .folder-name-container .folder-name-entry:hover, .search-entry:hover {
 +    background-color: #505050;
 +    color: whitesmoke; }
 +  .login-dialog .login-dialog-prompt-entry:focus, .app-folder-dialog .folder-name-container .folder-name-entry:focus, .search-entry:focus {
-   background-color: #464646; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #464646, 5%);
 +    color: whitesmoke; }
 +  .login-dialog .login-dialog-prompt-entry:insensitive, .app-folder-dialog .folder-name-container .folder-name-entry:insensitive, .search-entry:insensitive {
 +    background-color: #3e3e3e;
 +    color: rgba(245, 245, 245, 0.5); }
 +  .login-dialog .login-dialog-prompt-entry StLabel.hint-text, .app-folder-dialog .folder-name-container .folder-name-entry StLabel.hint-text, .search-entry StLabel.hint-text {
 +    color: rgba(245, 245, 245, 0.7); }
 +
 +.login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button {
 +  color: whitesmoke;
-     color: rgba(245, 245, 245, 0.5);
-     background-color: #3e3e3e; }
++  background-color: st-mix(whitesmoke, #353535, 9%); }
 +  .login-dialog-button.cancel-button:insensitive, .login-dialog-button.switch-user-button:insensitive, .login-dialog-button.login-dialog-session-list-button:insensitive {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #45494e; }
++    color: st-transparentize(whitesmoke, 0.5);
++    background-color: st-darken(st-mix(whitesmoke, #353535, 9%), 3%); }
 +  .login-dialog-button.cancel-button:focus, .login-dialog-button.switch-user-button:focus, .login-dialog-button.login-dialog-session-list-button:focus {
 +    color: whitesmoke;
-       background-color: #4f5358; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(whitesmoke, #353535, 9%), 5%); }
 +    .login-dialog-button.cancel-button:focus:hover, .login-dialog-button.switch-user-button:focus:hover, .login-dialog-button.login-dialog-session-list-button:focus:hover {
-     background-color: #505050; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #353535, 9%), 4%), 5%); }
 +  .login-dialog-button.cancel-button:hover, .login-dialog-button.switch-user-button:hover, .login-dialog-button.login-dialog-session-list-button:hover {
 +    color: whitesmoke;
-     background-color: #5d5d5d; }
++    background-color: st-lighten(st-mix(whitesmoke, #353535, 9%), 4%); }
 +  .login-dialog-button.cancel-button:active, .login-dialog-button.switch-user-button:active, .login-dialog-button.login-dialog-session-list-button:active {
 +    color: whitesmoke;
-       background-color: #676767; }
++    background-color: st-lighten(st-mix(whitesmoke, #353535, 9%), 9%); }
 +    .login-dialog-button.cancel-button:active:hover, .login-dialog-button.switch-user-button:active:hover, .login-dialog-button.login-dialog-session-list-button:active:hover {
-       background-color: #5b5f64; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #353535, 9%), 9%), 4%); }
 +    .login-dialog-button.cancel-button:active:focus, .login-dialog-button.switch-user-button:active:focus, .login-dialog-button.login-dialog-session-list-button:active:focus {
-     background-color: #5a5a5a; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #353535, 9%), 9%), 5%); }
 +  .login-dialog-button.cancel-button:checked, .login-dialog-button.switch-user-button:checked, .login-dialog-button.login-dialog-session-list-button:checked {
 +    color: whitesmoke;
-       background-color: #656565; }
++    background-color: st-lighten(st-mix(whitesmoke, #353535, 9%), 8%); }
 +    .login-dialog-button.cancel-button:checked:hover, .login-dialog-button.switch-user-button:checked:hover, .login-dialog-button.login-dialog-session-list-button:checked:hover {
-       background-color: #717171; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #353535, 9%), 8%), 4%); }
 +    .login-dialog-button.cancel-button:checked:active, .login-dialog-button.switch-user-button:checked:active, .login-dialog-button.login-dialog-session-list-button:checked:active {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(149, 189, 237, 0.145); }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #353535, 9%), 8%), 9%); }
 +
 +/* Lockscreen Elements */
 +.unlock-dialog .button,
 +.unlock-dialog .icon-button,
 +.unlock-dialog .calendar .calendar-month-header .pager-button,
 +.calendar .calendar-month-header .unlock-dialog .pager-button,
 +.unlock-dialog .message .message-header .message-expand-button,
 +.message .message-header .unlock-dialog .message-expand-button,
 +.unlock-dialog .message .message-header .message-close-button,
 +.message .message-header .unlock-dialog .message-close-button,
 +.unlock-dialog .screenshot-ui-show-pointer-button,
 +.unlock-dialog .login-dialog-button.cancel-button,
 +.unlock-dialog .login-dialog-button.switch-user-button,
 +.unlock-dialog .login-dialog-button.login-dialog-session-list-button {
 +  color: whitesmoke;
 +  background-color: rgba(245, 245, 245, 0.1); }
 +  .unlock-dialog .button:focus,
 +  .unlock-dialog .icon-button:focus,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:focus,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:focus,
 +  .unlock-dialog .message .message-header .message-expand-button:focus,
 +  .message .message-header .unlock-dialog .message-expand-button:focus,
 +  .unlock-dialog .message .message-header .message-close-button:focus,
 +  .message .message-header .unlock-dialog .message-close-button:focus,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:focus,
 +  .unlock-dialog .login-dialog-button.cancel-button:focus,
 +  .unlock-dialog .login-dialog-button.switch-user-button:focus,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:focus {
 +    color: whitesmoke;
-       background-color: rgba(162, 196, 238, 0.1735); }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.1), 5%); }
 +    .unlock-dialog .button:focus:hover,
 +    .unlock-dialog .icon-button:focus:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:focus:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:focus:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:focus:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:focus:hover,
 +    .unlock-dialog .message .message-header .message-close-button:focus:hover,
 +    .message .message-header .unlock-dialog .message-close-button:focus:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:focus:hover {
-       background-color: rgba(173, 202, 239, 0.202); }
++      background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.13), 5%); }
 +  .unlock-dialog .button:hover,
 +  .unlock-dialog .icon-button:hover,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:hover,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:hover,
 +  .unlock-dialog .message .message-header .message-expand-button:hover,
 +  .message .message-header .unlock-dialog .message-expand-button:hover,
 +  .unlock-dialog .message .message-header .message-close-button:hover,
 +  .message .message-header .unlock-dialog .message-close-button:hover,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:hover,
 +  .unlock-dialog .login-dialog-button.cancel-button:hover,
 +  .unlock-dialog .login-dialog-button.switch-user-button:hover,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:hover {
 +    color: whitesmoke;
 +    background-color: rgba(245, 245, 245, 0.13); }
 +  .unlock-dialog .button:active,
 +  .unlock-dialog .icon-button:active,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:active,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:active,
 +  .unlock-dialog .message .message-header .message-expand-button:active,
 +  .message .message-header .unlock-dialog .message-expand-button:active,
 +  .unlock-dialog .message .message-header .message-close-button:active,
 +  .message .message-header .unlock-dialog .message-close-button:active,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:active,
 +  .unlock-dialog .login-dialog-button.cancel-button:active,
 +  .unlock-dialog .login-dialog-button.switch-user-button:active,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active {
 +    color: whitesmoke;
 +    background-color: rgba(245, 245, 245, 0.16); }
 +    .unlock-dialog .button:active:hover,
 +    .unlock-dialog .icon-button:active:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:active:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:active:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:active:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:active:hover,
 +    .unlock-dialog .message .message-header .message-close-button:active:hover,
 +    .message .message-header .unlock-dialog .message-close-button:active:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:active:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:active:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:active:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active:hover {
 +      background-color: rgba(245, 245, 245, 0.19); }
 +    .unlock-dialog .button:active:focus,
 +    .unlock-dialog .icon-button:active:focus,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:active:focus,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:active:focus,
 +    .unlock-dialog .message .message-header .message-expand-button:active:focus,
 +    .message .message-header .unlock-dialog .message-expand-button:active:focus,
 +    .unlock-dialog .message .message-header .message-close-button:active:focus,
 +    .message .message-header .unlock-dialog .message-close-button:active:focus,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:active:focus,
 +    .unlock-dialog .login-dialog-button.cancel-button:active:focus,
 +    .unlock-dialog .login-dialog-button.switch-user-button:active:focus,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active:focus {
-     background-color: #5a5a5a; }
++      background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.16), 5%); }
 +  .unlock-dialog .button:checked,
 +  .unlock-dialog .icon-button:checked,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:checked,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:checked,
 +  .unlock-dialog .message .message-header .message-expand-button:checked,
 +  .message .message-header .unlock-dialog .message-expand-button:checked,
 +  .unlock-dialog .message .message-header .message-close-button:checked,
 +  .message .message-header .unlock-dialog .message-close-button:checked,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:checked,
 +  .unlock-dialog .login-dialog-button.cancel-button:checked,
 +  .unlock-dialog .login-dialog-button.switch-user-button:checked,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked {
 +    color: whitesmoke;
-       background-color: #656565; }
++    background-color: st-lighten(st-mix(whitesmoke, #353535, 9%), 8%); }
 +    .unlock-dialog .button:checked:hover,
 +    .unlock-dialog .icon-button:checked:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:checked:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:checked:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:checked:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:checked:hover,
 +    .unlock-dialog .message .message-header .message-close-button:checked:hover,
 +    .message .message-header .unlock-dialog .message-close-button:checked:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked:hover {
-       background-color: #717171; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #353535, 9%), 8%), 4%); }
 +    .unlock-dialog .button:checked:active,
 +    .unlock-dialog .icon-button:checked:active,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:checked:active,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:checked:active,
 +    .unlock-dialog .message .message-header .message-expand-button:checked:active,
 +    .message .message-header .unlock-dialog .message-expand-button:checked:active,
 +    .unlock-dialog .message .message-header .message-close-button:checked:active,
 +    .message .message-header .unlock-dialog .message-close-button:checked:active,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:checked:active,
 +    .unlock-dialog .login-dialog-button.cancel-button:checked:active,
 +    .unlock-dialog .login-dialog-button.switch-user-button:checked:active,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked:active {
-     color: rgba(245, 245, 245, 0.5);
-     background-color: #3e3e3e; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #353535, 9%), 8%), 9%); }
 +  .unlock-dialog .button:insensitive,
 +  .unlock-dialog .icon-button:insensitive,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:insensitive,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:insensitive,
 +  .unlock-dialog .message .message-header .message-expand-button:insensitive,
 +  .message .message-header .unlock-dialog .message-expand-button:insensitive,
 +  .unlock-dialog .message .message-header .message-close-button:insensitive,
 +  .message .message-header .unlock-dialog .message-close-button:insensitive,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:insensitive,
 +  .unlock-dialog .login-dialog-button.cancel-button:insensitive,
 +  .unlock-dialog .login-dialog-button.switch-user-button:insensitive,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:insensitive {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(149, 189, 237, 0.145);
++    color: st-transparentize(whitesmoke, 0.5);
++    background-color: st-darken(st-mix(whitesmoke, #353535, 9%), 3%); }
 +
 +.unlock-dialog .login-dialog-prompt-entry {
 +  background-color: rgba(245, 245, 245, 0.1);
 +  color: rgba(245, 245, 245, 0.7); }
 +  .unlock-dialog .login-dialog-prompt-entry:hover {
 +    background-color: rgba(255, 255, 255, 0.1);
 +    color: whitesmoke; }
 +  .unlock-dialog .login-dialog-prompt-entry:focus {
-     background-color: rgba(245, 245, 245, 0.115); }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.1), 5%);
 +    color: whitesmoke;
 +    box-shadow: inset 0 0 0 2px rgba(245, 245, 245, 0.4) !important;
-   color: #62a0ea; }
++    background-color: st-mix(rgba(245, 245, 245, 0.4), rgba(245, 245, 245, 0.1), 5%); }
 +  .unlock-dialog .login-dialog-prompt-entry:insensitive {
 +    background-color: rgba(237, 237, 237, 0.1);
 +    color: rgba(245, 245, 245, 0.5); }
 +  .unlock-dialog .login-dialog-prompt-entry StLabel.hint-text {
 +    color: rgba(245, 245, 245, 0.7); }
 +
 +/* WIDGETS */
 +.shell-link {
-     color: #8fbbf0; }
++  color: st-lighten(-st-accent-color, 20%); }
 +  .shell-link:hover {
-   width: 24px;
-   height: 24px;
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-off.svg"); }
++    color: st-lighten(st-lighten(-st-accent-color, 20%), 10%); }
 +
 +.lowres-icon {
 +  icon-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); }
 +
 +.icon-dropshadow {
 +  icon-shadow: 0 2px 4px rgba(0, 0, 0, 0.4); }
 +
 +/* Entries */
 +StEntry StIcon.capslock-warning {
 +  icon-size: 1.091em;
 +  warning-color: #f6d32d;
 +  padding: 0 4px; }
 +
 +StEntry StIcon.peek-password {
 +  icon-size: 1.091em;
 +  padding: 0 4px; }
 +
 +StEntry StLabel.hint-text {
 +  margin-left: 2px; }
 +
 +/* Buttons */
 +.button {
 +  min-height: 1.5em; }
 +
 +.icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .screenshot-ui-show-pointer-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button {
 +  border-radius: 999px;
 +  padding: 0.818em;
 +  min-height: 1.091em; }
 +  .icon-button StIcon, .login-dialog-button.cancel-button StIcon, .login-dialog-button.switch-user-button StIcon, .login-dialog-button.login-dialog-session-list-button StIcon, .screenshot-ui-show-pointer-button StIcon, .message .message-header .message-expand-button StIcon,
 +  .message .message-header .message-close-button StIcon, .calendar .calendar-month-header .pager-button StIcon {
 +    icon-size: 1.091em;
 +    -st-icon-style: symbolic; }
 +
 +/* Check Boxes */
 +.check-box StBoxLayout {
 +  spacing: .8em; }
 +
 +.check-box StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-off-focused.svg"); }
++  border-radius: 7px;
++  padding: 2px; }
 +
 +.check-box:focus StBin {
- .check-box:checked StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); }
++  background-color: rgba(0, 0, 0, 0.01);
++  box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.65); }
++
++.check-box StIcon {
++  icon-size: 14px;
++  padding: 1px;
++  color: transparent;
++  border-radius: 6px;
++  border: 2px solid rgba(255, 255, 255, 0.15); }
++
++.check-box:hover StIcon {
++  border-color: rgba(255, 255, 255, 0.2); }
++
++.check-box:active StIcon {
++  border-color: rgba(255, 255, 255, 0.3); }
++
++.check-box:checked StIcon {
++  background-color: -st-accent-color;
++  color: -st-accent-fg-color;
++  border-color: transparent; }
 +
- .check-box:focus:checked StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); }
++.check-box:checked:hover StIcon {
++  background-color: st-lighten(-st-accent-color, 5%);
++  color: st-lighten(-st-accent-fg-color, 5%); }
 +
-   color: #ffffff;
-   height: 26px;
++.check-box:checked:active StIcon {
++  background-color: st-darken(-st-accent-color, 7%);
++  color: st-darken(-st-accent-fg-color, 7%); }
 +
 +/* Switches */
 +.toggle-switch {
-   background-size: contain;
-   background-image: url("resource:///org/gnome/shell/theme/toggle-off.svg"); }
-   .toggle-switch:checked {
-     background-image: url("resource:///org/gnome/shell/theme/toggle-on.svg"); }
 +  width: 46px;
-   -barlevel-background-color: rgba(255, 255, 255, 0.2);
-   -barlevel-border-width: 2px;
-   -barlevel-border-color: transparent;
-   -barlevel-active-background-color: #3584e4;
-   -barlevel-active-border-color: transparent;
++  border-radius: 999px;
++  transition-duration: 100ms;
++  color: #ffffff;
++  background: rgba(255, 255, 255, 0.15); }
++  .toggle-switch:hover {
++    background: rgba(255, 255, 255, 0.2); }
 +  .toggle-switch StIcon {
 +    icon-size: 16px; }
++  .toggle-switch .handle {
++    margin: 3px;
++    width: 20px;
++    height: 20px;
++    border-radius: 999px;
++    background: #d7d7d7;
++    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
++    transition-duration: 100ms; }
++  .toggle-switch:checked {
++    background: -st-accent-color;
++    color: -st-accent-fg-color; }
++    .toggle-switch:checked:hover {
++      background-color: st-lighten(-st-accent-color, 5%);
++      color: st-lighten(-st-accent-fg-color, 5%); }
++    .toggle-switch:checked .handle {
++      background: white; }
 +
 +/* Slider */
 +.slider {
++  color: #e8e8e8;
 +  -barlevel-height: 4px;
-   -barlevel-overdrive-border-color: transparent;
++  -barlevel-background-color: rgba(255, 255, 255, 0.1);
++  -barlevel-active-background-color: -st-accent-color;
 +  -barlevel-overdrive-color: #c01c28;
-   -slider-handle-radius: 0.5455em;
-   -slider-handle-border-width: 0;
-   -slider-handle-border-color: transparent; }
 +  -barlevel-overdrive-separator-width: 1px;
-   .popup-menu-item:focus, .popup-menu-item:hover {
++  -slider-handle-radius: 0.5455em; }
++  .slider:hover {
++    color: #ffffff; }
 +
 +/* Scrollbars */
 +StScrollView.vfade {
 +  -st-vfade-offset: 68px; }
 +
 +StScrollView.hfade {
 +  -st-hfade-offset: 68px; }
 +
 +StScrollBar {
 +  padding: 0; }
 +  StScrollView StScrollBar {
 +    min-width: 8px;
 +    min-height: 8px; }
 +  StScrollBar StBin#trough {
 +    border-radius: 0;
 +    background-color: transparent; }
 +  StScrollBar StButton#vhandle, StScrollBar StButton#hhandle {
 +    border-radius: 8px;
 +    background-color: #717171;
 +    border: 3px solid transparent;
 +    transition: 500ms all ease; }
 +    StScrollBar StButton#vhandle:hover, StScrollBar StButton#hhandle:hover {
 +      background-color: #9a9a9a; }
 +    StScrollBar StButton#vhandle:active, StScrollBar StButton#hhandle:active {
 +      background-color: #868686; }
 +
 +/* Popovers/Menus */
 +.popup-menu-boxpointer, .candidate-popup-boxpointer {
 +  -arrow-rise: 6px; }
 +
 +.popup-menu {
 +  min-width: 15em;
 +  color: #ffffff; }
 +  .popup-menu.panel-menu {
 +    margin-bottom: 1.75em; }
 +
 +.popup-menu-content, .candidate-popup-content {
 +  padding: 6px;
 +  background-color: #353535;
 +  border-radius: 20px;
 +  border: 1px solid #424242;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2); }
 +
 +.popup-menu-item {
 +  background-color: transparent;
 +  border-color: transparent;
 +  box-shadow: none;
 +  border-radius: 12px; }
 +  .popup-menu-item:insensitive {
 +    background-color: transparent !important; }
-     background-color: #5d5d5d; }
++  .popup-menu-item:hover {
 +    color: #ffffff;
-     background-color: #6a6a6a; }
++    background-color: st-lighten(st-mix(#ffffff, #424242, 9%), 4%); }
 +  .popup-menu-item:active {
 +    color: #ffffff;
-       background-color: #747474; }
++    background-color: st-lighten(st-mix(#ffffff, #424242, 9%), 9%); }
 +    .popup-menu-item:active:hover {
-       background-color: #676b70; }
-   .popup-menu-item:checked {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #424242, 9%), 9%), 4%); }
 +    .popup-menu-item:active:focus {
-     background-color: #676767; }
-     .popup-menu-item:checked:hover {
-       background-color: #727272; }
-     .popup-menu-item:checked:active {
-       background-color: #7e7e7e; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #424242, 9%), 9%), 5%); }
++  .popup-menu-item:selected, .popup-menu-item:checked {
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #4b4b4b; }
++    background-color: st-lighten(st-mix(#ffffff, #424242, 9%), 8%); }
++    .popup-menu-item:selected:hover, .popup-menu-item:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #424242, 9%), 8%), 4%); }
++    .popup-menu-item:selected:active, .popup-menu-item:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #424242, 9%), 8%), 9%); }
 +  .popup-menu-item:insensitive {
-     .popup-sub-menu .popup-menu-item:focus, .popup-sub-menu .popup-menu-item:hover {
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #424242, 9%), 3%); }
 +  .popup-menu-item:checked {
 +    border-radius: 12px 12px 0 0 !important; }
 +  .popup-menu-item .toggle-switch:ltr {
 +    margin-left: 4px; }
 +  .popup-menu-item .toggle-switch:rtl {
 +    margin-right: 4px; }
 +
 +.popup-ornamented-menu-item:ltr {
 +  padding-left: 6px; }
 +
 +.popup-ornamented-menu-item:rtl {
 +  padding-right: 6px; }
 +
 +.popup-inactive-menu-item {
 +  color: #ffffff; }
 +  .popup-inactive-menu-item:insensitive {
 +    color: #9a9a9a; }
 +
 +.popup-menu-arrow,
 +.popup-menu-icon {
 +  icon-size: 1.091em; }
 +
 +.popup-sub-menu {
 +  border-radius: 0 0 13px 13px;
 +  margin-bottom: 6px;
 +  border: 1px solid transparent;
 +  background-color: #565656; }
 +  .popup-sub-menu .popup-menu-item {
 +    border-radius: 0;
 +    border-top-width: 0;
 +    background-color: transparent;
 +    border-color: transparent;
 +    box-shadow: none; }
 +    .popup-sub-menu .popup-menu-item:insensitive {
 +      background-color: transparent !important; }
-       background-color: #6f6f6f; }
++    .popup-sub-menu .popup-menu-item:hover {
 +      color: #ffffff;
-       background-color: #7c7c7c; }
++      background-color: st-lighten(st-mix(#ffffff, #565656, 9%), 4%); }
 +    .popup-sub-menu .popup-menu-item:active {
 +      color: #ffffff;
-         background-color: #868686; }
++      background-color: st-lighten(st-mix(#ffffff, #565656, 9%), 9%); }
 +      .popup-sub-menu .popup-menu-item:active:hover {
-         background-color: #787c81; }
-     .popup-sub-menu .popup-menu-item:checked {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #565656, 9%), 9%), 4%); }
 +      .popup-sub-menu .popup-menu-item:active:focus {
-       background-color: #797979; }
-       .popup-sub-menu .popup-menu-item:checked:hover {
-         background-color: #848484; }
-       .popup-sub-menu .popup-menu-item:checked:active {
-         background-color: #909090; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #565656, 9%), 9%), 5%); }
++    .popup-sub-menu .popup-menu-item:selected, .popup-sub-menu .popup-menu-item:checked {
 +      color: #ffffff;
-       color: rgba(255, 255, 255, 0.5);
-       background-color: #5d5d5d; }
++      background-color: st-lighten(st-mix(#ffffff, #565656, 9%), 8%); }
++      .popup-sub-menu .popup-menu-item:selected:hover, .popup-sub-menu .popup-menu-item:checked:hover {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #565656, 9%), 8%), 4%); }
++      .popup-sub-menu .popup-menu-item:selected:active, .popup-sub-menu .popup-menu-item:checked:active {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #565656, 9%), 8%), 9%); }
 +    .popup-sub-menu .popup-menu-item:insensitive {
-       color: #ffffff !important; }
++      color: st-transparentize(#ffffff, 0.5);
++      background-color: st-darken(st-mix(#ffffff, #565656, 9%), 3%); }
 +    .popup-sub-menu .popup-menu-item:last-child {
 +      border-radius: 0 0 12px 12px;
 +      border-bottom-width: 0; }
 +  .popup-sub-menu .popup-menu-section .popup-menu-item:last-child:hover, .popup-sub-menu .popup-menu-section .popup-menu-item:last-child:focus {
 +    border-radius: 0; }
 +  .popup-sub-menu .popup-menu-section:last-child .popup-menu-item:last-child {
 +    border-radius: 0 0 12px 12px; }
 +
 +.popup-menu-ornament {
 +  icon-size: 1.091em !important;
 +  width: 1.091em; }
 +
 +.popup-separator-menu-item {
 +  border: none !important; }
 +  .popup-separator-menu-item .popup-separator-menu-item-separator {
 +    height: 1px;
 +    background-color: rgba(255, 255, 255, 0.1); }
 +  .popup-sub-menu .popup-separator-menu-item {
 +    background-color: transparent; }
 +    .popup-sub-menu .popup-separator-menu-item:ltr {
 +      margin-right: 2.5em; }
 +    .popup-sub-menu .popup-separator-menu-item:rtl {
 +      margin-left: 2.5em; }
 +    .popup-sub-menu .popup-separator-menu-item .popup-separator-menu-item-separator {
 +      background-color: rgba(255, 255, 255, 0.1); }
 +
 +.background-menu {
 +  -boxpointer-gap: 0px;
 +  -arrow-rise: 0px; }
 +
 +.app-menu {
 +  max-width: 27.25em; }
 +  .app-menu .popup-inactive-menu-item:first-child > StLabel:ltr {
 +    margin-right: 8px; }
 +  .app-menu .popup-inactive-menu-item:first-child > StLabel:rtl {
 +    margin-left: 8px; }
 +
 +/* Date/Time Menu */
 +#calendarArea {
 +  padding: 4px; }
 +
 +.datemenu-popover {
 +  border-radius: 30px; }
 +
 +.datemenu-calendar-column {
 +  spacing: 6px; }
 +  .datemenu-calendar-column:ltr {
 +    margin-left: 6px; }
 +  .datemenu-calendar-column:rtl {
 +    margin-right: 6px; }
 +  .datemenu-calendar-column .datemenu-displays-box {
 +    spacing: 6px; }
 +
 +.datemenu-today-button {
 +  padding: 9px; }
 +  .datemenu-today-button .day-label {
 +    font-weight: bold; }
 +
 +.calendar {
 +  margin-top: 0;
 +  padding: 0; }
 +  .calendar .calendar-month-header .calendar-change-month-back StIcon,
 +  .calendar .calendar-month-header .calendar-change-month-forward StIcon {
 +    icon-size: 1.091em; }
 +  .calendar .calendar-month-header .calendar-month-label {
 +    color: #ffffff !important;
 +    padding: 8px 0;
 +    width: 10em;
 +    border-radius: 999px;
 +    text-align: center; }
 +  .calendar .calendar-month-header .pager-button {
 +    height: 2.6em;
 +    width: 2.6em;
 +    padding: 0; }
 +  .calendar .calendar-day {
 +    border-radius: 999px;
 +    height: 3em;
 +    width: 3em;
 +    margin: 2px;
 +    padding: 0;
 +    font-weight: bold;
 +    text-align: center; }
 +    .calendar .calendar-day.calendar-weekend {
 +      color: #9a9a9a; }
 +    .calendar .calendar-day.calendar-other-month {
 +      color: rgba(255, 255, 255, 0.5);
 +      font-weight: normal; }
 +      .calendar .calendar-day.calendar-other-month.calendar-weekend {
 +        color: rgba(255, 255, 255, 0.5); }
 +    .calendar .calendar-day.calendar-today {
-       border-color: rgba(53, 132, 228, 0.6); }
++      color: -st-accent-fg-color !important; }
 +      .calendar .calendar-day.calendar-today.calendar-day-with-events {
 +        background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg") !important; }
 +    .calendar .calendar-day.calendar-day-with-events {
 +      background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
 +      background-size: contain; }
 +  .calendar .calendar-day-heading {
 +    font-weight: bold;
 +    text-align: center;
 +    margin: 4px;
 +    padding: 3px 6px;
 +    border-radius: 8px; }
 +  .calendar .calendar-week-number {
 +    font-weight: bold;
 +    font-feature-settings: "tnum";
 +    text-align: center;
 +    margin: 6px;
 +    padding: 0 6px;
 +    border-radius: 4px;
 +    background-color: rgba(154, 154, 154, 0.2);
 +    color: #9a9a9a; }
 +
 +.events-button .events-box .events-title {
 +  color: #9a9a9a;
 +  padding-bottom: 6px; }
 +
 +.events-button .events-box .events-list {
 +  spacing: 6px; }
 +  .events-button .events-box .events-list .event-box {
 +    spacing: 6px;
 +    border-radius: 8px; }
 +    .events-button .events-box .events-list .event-box .event-time {
 +      color: #9a9a9a; }
 +  .events-button .events-box .events-list .event-placeholder {
 +    color: #9a9a9a;
 +    font-style: italic; }
 +
 +.world-clocks-button .world-clocks-header {
 +  color: #9a9a9a; }
 +  .world-clocks-button .world-clocks-header.no-world-clocks {
 +    color: #ffffff; }
 +
 +.world-clocks-button .world-clocks-grid {
 +  spacing-rows: 6px;
 +  spacing-columns: 12px; }
 +  .world-clocks-button .world-clocks-grid .world-clocks-time {
 +    font-weight: bold; }
 +    .world-clocks-button .world-clocks-grid .world-clocks-time:ltr {
 +      text-align: right; }
 +    .world-clocks-button .world-clocks-grid .world-clocks-time:rtl {
 +      text-align: left; }
 +  .world-clocks-button .world-clocks-grid .world-clocks-timezone {
 +    color: #9a9a9a; }
 +
 +.weather-button .weather-box {
 +  spacing: 6px; }
 +  .weather-button .weather-box .weather-header-box {
 +    spacing: 6px; }
 +    .weather-button .weather-box .weather-header-box .weather-header {
 +      color: #9a9a9a; }
 +      .weather-button .weather-box .weather-header-box .weather-header.no-location {
 +        color: #ffffff; }
 +      .weather-button .weather-box .weather-header-box .weather-header.location {
 +        font-weight: normal; }
 +  .weather-button .weather-box .weather-grid {
 +    spacing-rows: 6px;
 +    spacing-columns: 12px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-time {
 +      padding-top: 6px;
 +      padding-bottom: 6px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-icon {
 +      icon-size: 2.182em;
 +      margin-bottom: 4px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-temp {
 +      font-weight: bold; }
 +
 +/* Message List */
 +.message-list {
 +  width: 29em;
 +  border: solid rgba(255, 255, 255, 0.1); }
 +  .message-list:ltr {
 +    margin-left: 0;
 +    margin-right: 4px;
 +    padding-right: 6px;
 +    border-right-width: 1px; }
 +  .message-list:rtl {
 +    margin-right: 0;
 +    margin-left: 4px;
 +    padding-left: 6px;
 +    border-left-width: 1px; }
 +  .message-list .message-list-placeholder {
 +    color: rgba(255, 255, 255, 0.25); }
 +    .message-list .message-list-placeholder > StIcon {
 +      icon-size: 96px;
 +      margin-bottom: 12px;
 +      -st-icon-style: symbolic; }
 +
 +.message-list-sections {
 +  spacing: 12px; }
 +  .message-list-sections:ltr {
 +    margin-right: 12px; }
 +  .message-list-sections:rtl {
 +    margin-left: 12px; }
 +
 +.message-list-section,
 +.message-list-section-list {
 +  spacing: 12px; }
 +
 +.message-list-controls {
 +  padding: 12px;
 +  padding-bottom: 6px;
 +  spacing: 6px; }
 +  .message-list-controls .dnd-button {
 +    border-width: 2px;
 +    border-color: transparent;
 +    border-radius: 32px;
 +    border-style: solid; }
 +    .message-list-controls .dnd-button:focus {
-   padding: 0;
++      border-color: st-transparentize(-st-accent-color, 0.4); }
 +
 +.message {
-   .message:ltr {
-     padding-right: -2px; }
-   .message:rtl {
-     padding-left: -2px; }
++  padding: 6px;
 +  margin: 0;
 +  border-radius: 16px; }
-     padding: 0 0.409em;
-     margin: 6px;
-     margin-bottom: 0;
 +  .message .message-header {
-     color: #9a9a9a; }
 +    spacing: 6px;
-       background-color: rgba(255, 255, 255, 0.1);
++    color: #9a9a9a;
++    padding: 0 6px; }
++    .message .message-header:ltr {
++      padding-right: 4px; }
++    .message .message-header:rtl {
++      padding-left: 4px; }
 +    .message .message-header .message-source-icon {
 +      icon-size: 1.091em;
 +      -st-icon-style: symbolic; }
 +    .message .message-header .message-header-content {
 +      spacing: 6px;
 +      min-height: 1.637em;
 +      padding-bottom: 6px; }
 +      .message .message-header .message-header-content .message-source-title {
 +        font-weight: bold; }
 +      .message .message-header .message-header-content .event-time {
 +        color: #9a9a9a;
 +        padding-bottom: 0.068em; }
 +        .message .message-header .message-header-content .event-time:ltr {
 +          text-align: right; }
 +        .message .message-header .message-header-content .event-time:rtl {
 +          text-align: left; }
 +    .message .message-header .message-expand-button,
 +    .message .message-header .message-close-button {
++      border-radius: 999px;
 +      color: #ffffff;
-       .message .message-header .message-expand-button:hover,
-       .message .message-header .message-close-button:hover {
-         background-color: rgba(255, 255, 255, 0.19); }
-       .message .message-header .message-expand-button:active, .message .message-header .message-expand-button:active:hover,
-       .message .message-header .message-close-button:active,
-       .message .message-header .message-close-button:active:hover {
-         background-color: rgba(255, 255, 255, 0.24); }
-       .message .message-header .message-expand-button:insensitive,
-       .message .message-header .message-close-button:insensitive {
-         background-color: rgba(255, 255, 255, 0.07); }
 +      padding: 4px; }
-     margin: 6px;
 +    .message .message-header .message-expand-button {
 +      padding: 6px; }
 +      .message .message-header .message-expand-button:ltr {
 +        margin-right: 6px; }
 +      .message .message-header .message-expand-button:rtl {
 +        margin-left: 6px; }
 +  .message .message-box {
 +    padding: 6px;
-   link-color: #62a0ea; }
 +    margin-top: 0;
 +    spacing: 6px; }
 +    .message .message-box .message-icon {
 +      icon-size: 48px; }
 +      .message .message-box .message-icon:ltr {
 +        margin-right: 6px; }
 +      .message .message-box .message-icon:rtl {
 +        margin-left: 6px; }
 +      .message .message-box .message-icon.message-themed-icon {
 +        border-radius: 999px;
 +        background-color: rgba(255, 255, 255, 0.07);
 +        icon-size: 1.091em;
 +        min-width: 48px;
 +        min-height: 48px; }
 +    .message .message-box:first-child {
 +      margin-top: 12px; }
 +    .message .message-box .message-content {
 +      spacing: 4px; }
 +      .message .message-box .message-content .message-title {
 +        font-weight: bold; }
++  .message .message-action-bin {
++    padding: 4px;
++    spacing: 6px; }
++    .message .message-action-bin * {
++      margin: 0 4px; }
++      .message .message-action-bin *:first-child:ltr {
++        margin-left: 0; }
++      .message .message-action-bin *:first-child:rtl {
++        margin-right: 0; }
++      .message .message-action-bin *:last-child:ltr {
++        margin-right: 0; }
++      .message .message-action-bin *:last-child:rtl {
++        margin-left: 0; }
 +
 +.url-highlighter {
-     background-color: #3584e4;
-     color: #ffffff; }
++  link-color: st-lighten(-st-accent-color, 20%); }
 +
 +/* Media Controls */
 +.message-media-control {
 +  padding: 0 18px;
 +  border-radius: 8px;
 +  color: #ffffff;
 +  border: 1px solid transparent; }
 +  .message-media-control:hover {
 +    background-color: #5b5b5b;
 +    color: #ffffff; }
 +  .message-media-control:active {
 +    background-color: #606060;
 +    color: #ffffff; }
 +  .message-media-control:insensitive {
 +    color: #a7a7a7; }
 +  .message-media-control StIcon {
 +    icon-size: 16px; }
 +
 +.media-message .message-icon {
 +  border-radius: 8px !important; }
 +  .media-message .message-icon.message-themed-icon {
 +    icon-size: 32px !important; }
 +
 +.candidate-popup-content {
 +  padding: 6px;
 +  spacing: 6px; }
 +
 +.candidate-index {
 +  padding: 0;
 +  padding-right: 6px;
 +  color: #9a9a9a; }
 +
 +.candidate-box {
 +  padding: 6px 12px 6px 12px;
 +  border-radius: 8px; }
 +  .candidate-box:selected {
-   border-radius: 16px;
-   box-shadow: inset 0 0 0 1px #424242; }
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +  .candidate-box:hover {
 +    background-color: #4e4e4e;
 +    color: white; }
 +
 +.candidate-page-button-box {
 +  height: 2em; }
 +  .vertical .candidate-page-button-box {
 +    padding-top: 12px; }
 +  .horizontal .candidate-page-button-box {
 +    padding-left: 12px; }
 +
 +.candidate-page-button {
 +  padding: 6px; }
 +  .candidate-page-button StIcon {
 +    icon-size: 16px; }
 +
 +.candidate-page-button-previous {
 +  border-radius: 8px 0px 0px 8px;
 +  border-right-width: 0;
 +  box-shadow: none; }
 +
 +.candidate-page-button-next {
 +  border-radius: 0px 8px 8px 0px;
 +  box-shadow: none; }
 +
 +/* Notifications & Message Tray */
 +.notification-banner {
 +  min-height: 64px;
 +  width: 34em;
 +  box-shadow: 0 2px 4px 2px rgba(0, 0, 0, 0.2);
 +  border-radius: 16px;
 +  margin: 4px; }
 +
 +.notification-buttons-bin {
 +  spacing: 0; }
 +
 +/* Modal Dialogs */
 +.modal-dialog {
 +  background-color: #353535;
-     margin: 32px 40px;
++  border-radius: 18px;
++  box-shadow: inset 0 0 0 1px #424242;
++  padding: 24px; }
 +  .modal-dialog .modal-dialog-content-box {
-   width: 30em; }
 +    spacing: 32px;
++    margin-top: 8px;
++    margin-bottom: 16px;
 +    max-width: 28em; }
 +
 +/* End Session Dialog */
 +.end-session-dialog {
-     background-color: #3584e4;
-     color: #ffffff; }
++  width: 24em; }
 +  .end-session-dialog .end-session-dialog-battery-warning,
 +  .end-session-dialog .dialog-list-title {
 +    color: #f6d32d; }
 +
 +/* Message Dialog */
 +.message-dialog-content {
 +  spacing: 18px; }
 +  .message-dialog-content .message-dialog-title {
 +    text-align: center; }
 +  .message-dialog-content .message-dialog-description {
 +    text-align: center; }
 +
 +/* Dialog List */
 +.dialog-list {
 +  spacing: 18px; }
 +  .dialog-list .dialog-list-title {
 +    text-align: center; }
 +  .dialog-list .dialog-list-scrollview {
 +    max-height: 200px; }
 +  .dialog-list .dialog-list-box {
 +    spacing: 1em; }
 +    .dialog-list .dialog-list-box .dialog-list-item {
 +      spacing: 1em; }
 +      .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-title {
 +        font-weight: bold; }
 +      .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-description {
 +        color: #f2f2f2; }
 +
 +/* Run Dialog */
 +.run-dialog .modal-dialog-content-box {
 +  margin-top: 24px;
 +  margin-bottom: 12px; }
 +
 +.run-dialog .run-dialog-entry {
 +  width: 20em; }
 +
 +.run-dialog .run-dialog-description {
 +  text-align: center;
 +  color: #cccccc; }
 +
 +/* Password or Authentication Dialog */
 +.prompt-dialog {
 +  width: 28em; }
 +  .prompt-dialog .modal-dialog-content-box {
 +    margin-bottom: 24px; }
 +
 +.prompt-dialog-password-grid {
 +  spacing-rows: 8px;
 +  spacing-columns: 4px; }
 +  .prompt-dialog-password-grid .prompt-dialog-password-entry {
 +    width: auto; }
 +    .prompt-dialog-password-grid .prompt-dialog-password-entry:ltr {
 +      margin-left: 20px; }
 +    .prompt-dialog-password-grid .prompt-dialog-password-entry:rtl {
 +      margin-right: 20px; }
 +
 +.prompt-dialog-password-layout {
 +  spacing: 8px; }
 +
 +.prompt-dialog-password-entry {
 +  width: 20em; }
 +
 +.prompt-dialog-error-label,
 +.prompt-dialog-info-label,
 +.prompt-dialog-null-label {
 +  text-align: center; }
 +
 +.prompt-dialog-error-label {
 +  color: #f6d32d; }
 +
 +/* Polkit Dialog */
 +.polkit-dialog-user-layout {
 +  text-align: center;
 +  spacing: 8px;
 +  margin-bottom: 6px; }
 +  .polkit-dialog-user-layout .polkit-dialog-user-root-label {
 +    color: #f6d32d; }
 +
 +/* Audio selection dialog */
 +.audio-device-selection-dialog .modal-dialog-content-box {
 +  margin-bottom: 28px; }
 +
 +.audio-device-selection-dialog .audio-selection-box {
 +  spacing: 20px; }
 +
 +.audio-selection-device {
 +  border-radius: 16px; }
 +  .audio-selection-device:hover, .audio-selection-device:focus {
 +    background-color: #4e4e4e; }
 +  .audio-selection-device:active {
-   background-color: #3584e4;
-   color: #ffffff;
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +
 +.audio-selection-device-box {
 +  padding: 20px;
 +  spacing: 20px; }
 +
 +.audio-selection-device-icon {
 +  icon-size: 64px; }
 +
 +/* Welcome dialog */
 +.welcome-dialog-image {
 +  background-image: url("resource:///org/gnome/shell/theme/gnome-shell-start.svg");
 +  background-size: contain;
 +  /* Reasonable maximum dimensions */
 +  height: 300px;
 +  width: 300px; }
 +
 +/* Access portal dialog */
 +.access-dialog {
 +  text-align: center; }
 +
 +/* OSD */
 +.osd-window {
 +  text-align: center;
 +  font-weight: bold;
 +  spacing: 12px;
 +  padding: 12px 18px;
 +  margin-bottom: 4em; }
 +  .osd-window > * {
 +    spacing: 8px; }
 +  .osd-window StIcon {
 +    icon-size: 32px; }
 +  .osd-window StLabel:ltr {
 +    margin-right: 6px; }
 +  .osd-window StLabel:rtl {
 +    margin-left: 6px; }
 +  .osd-window .level {
 +    margin-bottom: 4px;
 +    min-width: 160px;
 +    -barlevel-height: 6px;
 +    -barlevel-background-color: rgba(255, 255, 255, 0.1);
 +    -barlevel-active-background-color: #ffffff;
 +    -barlevel-overdrive-color: #c01c28;
 +    -barlevel-overdrive-separator-width: 3px; }
 +    .osd-window .level:first-child {
 +      margin-bottom: 0; }
 +    .osd-window .level:ltr {
 +      margin-right: 6px; }
 +    .osd-window .level:rtl {
 +      margin-left: 6px; }
 +
 +.osd-monitor-label {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-       background-color: rgba(53, 74, 100, 0.2875); }
++  background-color: -st-accent-color;
++  color: -st-accent-fg-color;
 +  border-radius: 16px;
 +  font-size: 3em;
 +  font-weight: bold;
 +  font-feature-settings: "tnum";
 +  margin: 12px;
 +  padding: 12px;
 +  text-align: center;
 +  min-width: 1.5em; }
 +
 +/* Pad OSD */
 +.pad-osd-window {
 +  padding: 32px;
 +  background-color: rgba(0, 0, 0, 0.8); }
 +  .pad-osd-window .pad-osd-title-box {
 +    spacing: 12px; }
 +  .pad-osd-window .pad-osd-title-menu-box {
 +    spacing: 6px; }
 +
 +.combo-box-label {
 +  width: 15em; }
 +
 +/* App Switcher */
 +.switcher-popup {
 +  padding: 0;
 +  spacing: 24px; }
 +
 +.switcher-list {
 +  padding: 12px;
 +  border-radius: 28px;
 +  box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.2); }
 +  .switcher-list .switcher-list-item-container {
 +    spacing: 12px; }
 +  .switcher-list .item-box {
 +    color: #ffffff;
 +    background-color: #353535; }
 +    .switcher-list .item-box:focus {
 +      color: #ffffff;
-         background-color: #464a4e; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, rgba(53, 53, 53, 0.25), 5%); }
 +      .switcher-list .item-box:focus:hover {
-       background-color: #474747; }
++        background-color: st-mix(-st-accent-color, st-lighten(#353535, 7%), 5%); }
 +    .switcher-list .item-box:hover {
 +      color: #ffffff;
-       background-color: #4c4c4c; }
++      background-color: st-lighten(#353535, 7%); }
 +    .switcher-list .item-box:active {
 +      color: #ffffff;
-         background-color: #5e5e5e; }
++      background-color: st-lighten(#353535, 9%); }
 +      .switcher-list .item-box:active:hover {
-         background-color: #4b4f53; }
++        background-color: st-lighten(st-lighten(#353535, 9%), 7%); }
 +      .switcher-list .item-box:active:focus {
-       background-color: #494949; }
++        background-color: st-mix(-st-accent-color, st-lighten(#353535, 9%), 5%); }
 +    .switcher-list .item-box:highlighted, .switcher-list .item-box:selected, .switcher-list .item-box:checked {
 +      color: #ffffff;
-         background-color: #5b5b5b; }
++      background-color: st-lighten(#353535, 8%); }
 +      .switcher-list .item-box:highlighted:hover, .switcher-list .item-box:selected:hover, .switcher-list .item-box:checked:hover {
-         background-color: #606060; }
++        background-color: st-lighten(st-lighten(#353535, 8%), 7%); }
 +      .switcher-list .item-box:highlighted:active, .switcher-list .item-box:selected:active, .switcher-list .item-box:checked:active {
-       color: rgba(255, 255, 255, 0.5);
++        background-color: st-lighten(st-lighten(#353535, 8%), 9%); }
 +    .switcher-list .item-box:insensitive {
-       background-color: rgba(53, 132, 228, 0.2);
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++      color: st-transparentize(#ffffff, 0.5);
 +      background-color: #353535; }
 +    .switcher-list .item-box:drop {
-   border: 5px solid #3584e4; }
++      background-color: st-transparentize(-st-accent-color, 0.8);
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +    .switcher-list .item-box:hover {
 +      background: none; }
 +    .switcher-list .item-box:selected {
 +      background-color: rgba(255, 255, 255, 0.2); }
 +  .switcher-list .separator {
 +    width: 1px;
 +    background: rgba(255, 255, 255, 0.1); }
 +  .switcher-list .thumbnail-box {
 +    padding: 2px;
 +    spacing: 6px; }
 +  .switcher-list .thumbnail {
 +    width: 256px;
 +    border-radius: 8px; }
 +
 +.switcher-arrow {
 +  border-color: rgba(255, 255, 255, 0.8);
 +  color: rgba(255, 255, 255, 0.8); }
 +  .switcher-arrow:highlighted {
 +    border-color: #ffffff;
 +    color: #ffffff; }
 +
 +.input-source-switcher-symbol {
 +  font-size: 34pt;
 +  width: 96px;
 +  height: 96px; }
 +
 +.cycler-highlight {
-   border-color: #185fb4; }
++  border: 5px solid -st-accent-color; }
 +
 +/* Workspace Switcher */
 +.workspace-switcher {
 +  margin-bottom: 4em;
 +  spacing: 12px;
 +  padding: 12px 18px; }
 +
 +.ws-switcher-indicator {
 +  background-color: rgba(255, 255, 255, 0.5);
 +  padding: 2.6666666667px;
 +  margin: 13.3333333333px;
 +  border-radius: 32px; }
 +  .ws-switcher-indicator:active {
 +    background-color: #ffffff;
 +    padding: 5.3333333333px;
 +    margin: 10.6666666667px; }
 +
 +.screenshot-ui-panel {
 +  border-radius: 32px;
 +  padding: 18px;
 +  padding-bottom: 12px;
 +  margin-bottom: 4em;
 +  spacing: 12px; }
 +
 +.screenshot-ui-close-button {
 +  padding: 6px !important;
 +  margin-top: 12px;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2); }
 +  .screenshot-ui-close-button.left {
 +    margin-left: 12px; }
 +  .screenshot-ui-close-button.right {
 +    margin-right: 12px; }
 +
 +.screenshot-ui-type-button {
 +  min-width: 48px;
 +  padding: 12px 18px;
 +  border-radius: 14px; }
 +  .screenshot-ui-type-button .icon-label-button-container {
 +    spacing: 0.409em; }
 +    .screenshot-ui-type-button .icon-label-button-container > StIcon {
 +      icon-size: 32px; }
 +
 +.screenshot-ui-capture-button {
 +  width: 32px;
 +  height: 32px;
 +  border-radius: 999px;
 +  border: 4px #ffffff;
 +  padding: 4px; }
 +  .screenshot-ui-capture-button .screenshot-ui-capture-button-circle {
 +    background-color: #ffffff;
 +    transition-duration: 200ms;
 +    border-radius: 999px; }
 +    .screenshot-ui-capture-button .screenshot-ui-capture-button-circle:hover, .screenshot-ui-capture-button .screenshot-ui-capture-button-circle:focus {
 +      background-color: #4e4e4e; }
 +  .screenshot-ui-capture-button:hover .screenshot-ui-capture-button-circle, .screenshot-ui-capture-button:focus .screenshot-ui-capture-button-circle {
 +    background-color: #cccccc; }
 +  .screenshot-ui-capture-button:active .screenshot-ui-capture-button-circle {
 +    background-color: gray; }
 +  .screenshot-ui-capture-button:cast .screenshot-ui-capture-button-circle {
 +    background-color: #c01c28; }
 +  .screenshot-ui-capture-button:cast:hover .screenshot-ui-capture-button-circle, .screenshot-ui-capture-button:cast:focus .screenshot-ui-capture-button-circle {
 +    background-color: #d61f2d; }
 +  .screenshot-ui-capture-button:cast:active .screenshot-ui-capture-button-circle {
 +    background-color: #a11722; }
 +
 +.screenshot-ui-shot-cast-container {
 +  background-color: rgba(255, 255, 255, 0.1);
 +  border-radius: 999px;
 +  padding: 3px;
 +  spacing: 3px; }
 +
 +.screenshot-ui-shot-cast-button {
 +  padding: 6px 12px;
 +  background-color: transparent;
 +  border-radius: 999px; }
 +  .screenshot-ui-shot-cast-button > StIcon {
 +    icon-size: 16px; }
 +  .screenshot-ui-shot-cast-button:hover, .screenshot-ui-shot-cast-button:focus {
 +    background-color: rgba(255, 255, 255, 0.2); }
 +  .screenshot-ui-shot-cast-button:active {
 +    background-color: rgba(255, 255, 255, 0.5); }
 +  .screenshot-ui-shot-cast-button:checked {
 +    background-color: #ffffff;
 +    color: #353535; }
 +  .screenshot-ui-shot-cast-button:insensitive {
 +    color: rgba(255, 255, 255, 0.5); }
 +
 +.screenshot-ui-area-indicator-shade {
 +  background-color: rgba(0, 0, 0, 0.3); }
 +
 +.screenshot-ui-area-selector .screenshot-ui-area-indicator-shade {
 +  background-color: rgba(0, 0, 0, 0.5); }
 +
 +.screenshot-ui-area-selector .screenshot-ui-area-indicator-selection {
 +  border: 2px white; }
 +
 +.screenshot-ui-area-selector-handle {
 +  border-radius: 999px;
 +  background-color: white;
 +  box-shadow: 0 1px 3px 2px rgba(0, 0, 0, 0.2);
 +  width: 24px;
 +  height: 24px; }
 +
 +.screenshot-ui-window-selector {
 +  background-color: #282828; }
 +  .screenshot-ui-window-selector .screenshot-ui-window-selector-window-container {
 +    margin: 100px; }
 +  .screenshot-ui-window-selector:primary-monitor .screenshot-ui-window-selector-window-container {
 +    margin-bottom: 200px; }
 +
 +.screenshot-ui-window-selector-window-border {
 +  transition-duration: 200ms;
 +  border-radius: 16px;
 +  border: 6px transparent; }
 +
 +.screenshot-ui-window-selector-check {
 +  transition-duration: 200ms;
 +  color: transparent;
 +  border-radius: 999px;
 +  border-width: 12px;
 +  icon-size: 24px; }
 +
 +.screenshot-ui-window-selector-window:hover .screenshot-ui-window-selector-window-border {
-   border-color: #3584e4;
-   background-color: rgba(53, 132, 228, 0.2); }
++  border-color: st-darken(-st-accent-color, 15%); }
 +
 +.screenshot-ui-window-selector-window:checked .screenshot-ui-window-selector-window-border {
-   color: #ffffff;
-   background-color: #3584e4; }
++  border-color: -st-accent-color;
++  background-color: st-transparentize(-st-accent-color, 0.8); }
 +
 +.screenshot-ui-window-selector-window:checked .screenshot-ui-window-selector-check {
-     border-color: #78aded; }
++  color: -st-accent-fg-color;
++  background-color: -st-accent-color; }
 +
 +.screenshot-ui-screen-selector {
 +  transition-duration: 200ms;
 +  background-color: rgba(0, 0, 0, 0.5); }
 +  .screenshot-ui-screen-selector:hover {
 +    background-color: rgba(0, 0, 0, 0.3); }
 +  .screenshot-ui-screen-selector:active {
 +    background-color: rgba(0, 0, 0, 0.7); }
 +  .screenshot-ui-screen-selector:checked {
 +    background-color: transparent;
 +    border: 2px white; }
 +
 +.screenshot-ui-tooltip {
 +  text-align: center;
 +  -y-offset: 24px; }
 +
 +/* Top Bar */
 +#panel {
 +  background-color: #000000;
 +  font-weight: bold;
 +  height: 2.2em;
 +  transition-duration: 250ms; }
 +  #panel .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 100px transparent;
 +    -natural-hpadding: 12px;
 +    -minimum-hpadding: 6px; }
 +    #panel .panel-button:focus, #panel .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +    #panel .panel-button:active, #panel .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +      #panel .panel-button:active:hover, #panel .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +    #panel .panel-button .system-status-icon {
 +      icon-size: 1.091em;
 +      padding: 0 6px;
 +      margin: 0 4px; }
 +    #panel .panel-button .app-menu-icon {
 +      -st-icon-style: symbolic; }
 +    #panel .panel-button .panel-status-menu-box,
 +    #panel .panel-button .panel-status-indicators-box {
 +      spacing: 4px; }
 +      #panel .panel-button .panel-status-menu-box > .system-status-icon,
 +      #panel .panel-button .panel-status-indicators-box > .system-status-icon {
 +        padding: 0; }
 +    #panel .panel-button#panelActivities StBoxLayout {
 +      padding: 0 0.2045em;
 +      spacing: 5px; }
 +    #panel .panel-button#panelActivities .workspace-dot {
 +      border-radius: 999px;
 +      min-width: 0.5455em;
 +      min-height: 0.5455em;
 +      background-color: #ffffff; }
 +    #panel .panel-button.screen-recording-indicator StBoxLayout, #panel .panel-button.screen-sharing-indicator StBoxLayout {
 +      spacing: 0.409em; }
 +    #panel .panel-button.screen-recording-indicator StIcon, #panel .panel-button.screen-sharing-indicator StIcon {
 +      icon-size: 1.091em; }
 +    #panel .panel-button.screen-recording-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #c01c28; }
 +      #panel .panel-button.screen-recording-indicator:focus, #panel .panel-button.screen-recording-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #d61f2d; }
 +      #panel .panel-button.screen-recording-indicator:active, #panel .panel-button.screen-recording-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #e02a37; }
 +        #panel .panel-button.screen-recording-indicator:active:hover, #panel .panel-button.screen-recording-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #e13340; }
 +    #panel .panel-button.screen-sharing-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #ff7800; }
 +      #panel .panel-button.screen-sharing-indicator:focus, #panel .panel-button.screen-sharing-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #ff861a; }
 +      #panel .panel-button.screen-sharing-indicator:active, #panel .panel-button.screen-sharing-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #ff902e; }
 +        #panel .panel-button.screen-sharing-indicator:active:hover, #panel .panel-button.screen-sharing-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #ff9638; }
 +    #panel .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #ffffff;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel .panel-button.clock-display:focus, #panel .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel .panel-button.clock-display:active, #panel .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel .panel-button.clock-display:active:hover, #panel .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel .panel-button.clock-display:focus .clock, #panel .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel .panel-button.clock-display:active .clock, #panel .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel .panel-button.clock-display:active .clock:hover, #panel .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel .panel-button.clock-display .messages-indicator {
 +        icon-size: 1.091em; }
 +  #panel:overview, #panel.unlock-screen, #panel.login-screen {
 +    background-color: transparent; }
 +    #panel:overview .panel-button.screen-recording-indicator, #panel.unlock-screen .panel-button.screen-recording-indicator, #panel.login-screen .panel-button.screen-recording-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #c01c28; }
 +      #panel:overview .panel-button.screen-recording-indicator:focus, #panel:overview .panel-button.screen-recording-indicator:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:focus, #panel.unlock-screen .panel-button.screen-recording-indicator:hover, #panel.login-screen .panel-button.screen-recording-indicator:focus, #panel.login-screen .panel-button.screen-recording-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #d61f2d; }
 +      #panel:overview .panel-button.screen-recording-indicator:active, #panel:overview .panel-button.screen-recording-indicator:checked, #panel.unlock-screen .panel-button.screen-recording-indicator:active, #panel.unlock-screen .panel-button.screen-recording-indicator:checked, #panel.login-screen .panel-button.screen-recording-indicator:active, #panel.login-screen .panel-button.screen-recording-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #e02a37; }
 +        #panel:overview .panel-button.screen-recording-indicator:active:hover, #panel:overview .panel-button.screen-recording-indicator:checked:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:active:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:checked:hover, #panel.login-screen .panel-button.screen-recording-indicator:active:hover, #panel.login-screen .panel-button.screen-recording-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #e13340; }
 +    #panel:overview .panel-button.screen-sharing-indicator, #panel.unlock-screen .panel-button.screen-sharing-indicator, #panel.login-screen .panel-button.screen-sharing-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #ff7800; }
 +      #panel:overview .panel-button.screen-sharing-indicator:focus, #panel:overview .panel-button.screen-sharing-indicator:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:focus, #panel.unlock-screen .panel-button.screen-sharing-indicator:hover, #panel.login-screen .panel-button.screen-sharing-indicator:focus, #panel.login-screen .panel-button.screen-sharing-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #ff861a; }
 +      #panel:overview .panel-button.screen-sharing-indicator:active, #panel:overview .panel-button.screen-sharing-indicator:checked, #panel.unlock-screen .panel-button.screen-sharing-indicator:active, #panel.unlock-screen .panel-button.screen-sharing-indicator:checked, #panel.login-screen .panel-button.screen-sharing-indicator:active, #panel.login-screen .panel-button.screen-sharing-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #ff902e; }
 +        #panel:overview .panel-button.screen-sharing-indicator:active:hover, #panel:overview .panel-button.screen-sharing-indicator:checked:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:active:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:checked:hover, #panel.login-screen .panel-button.screen-sharing-indicator:active:hover, #panel.login-screen .panel-button.screen-sharing-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #ff9638; }
 +  #panel.unlock-screen .panel-button, #panel.login-screen .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 100px transparent; }
 +    #panel.unlock-screen .panel-button:focus, #panel.unlock-screen .panel-button:hover, #panel.login-screen .panel-button:focus, #panel.login-screen .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +    #panel.unlock-screen .panel-button:active, #panel.unlock-screen .panel-button:checked, #panel.login-screen .panel-button:active, #panel.login-screen .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +      #panel.unlock-screen .panel-button:active:hover, #panel.unlock-screen .panel-button:checked:hover, #panel.login-screen .panel-button:active:hover, #panel.login-screen .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +    #panel.unlock-screen .panel-button.clock-display, #panel.login-screen .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #ffffff;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel.unlock-screen .panel-button.clock-display:focus, #panel.unlock-screen .panel-button.clock-display:hover, #panel.login-screen .panel-button.clock-display:focus, #panel.login-screen .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel.unlock-screen .panel-button.clock-display:active, #panel.unlock-screen .panel-button.clock-display:checked, #panel.login-screen .panel-button.clock-display:active, #panel.login-screen .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel.unlock-screen .panel-button.clock-display:active:hover, #panel.unlock-screen .panel-button.clock-display:checked:hover, #panel.login-screen .panel-button.clock-display:active:hover, #panel.login-screen .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel.unlock-screen .panel-button.clock-display .clock, #panel.login-screen .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel.unlock-screen .panel-button.clock-display:focus .clock, #panel.unlock-screen .panel-button.clock-display:hover .clock, #panel.login-screen .panel-button.clock-display:focus .clock, #panel.login-screen .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel.unlock-screen .panel-button.clock-display:active .clock, #panel.unlock-screen .panel-button.clock-display:checked .clock, #panel.login-screen .panel-button.clock-display:active .clock, #panel.login-screen .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel.unlock-screen .panel-button.clock-display:active .clock:hover, #panel.unlock-screen .panel-button.clock-display:checked .clock:hover, #panel.login-screen .panel-button.clock-display:active .clock:hover, #panel.login-screen .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +  #panel:overview .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: whitesmoke;
 +    box-shadow: inset 0 0 0 100px transparent; }
 +    #panel:overview .panel-button:focus, #panel:overview .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.17); }
 +    #panel:overview .panel-button:active, #panel:overview .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.28); }
 +      #panel:overview .panel-button:active:hover, #panel:overview .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.32); }
 +    #panel:overview .panel-button#panelActivities .workspace-dot {
 +      background-color: whitesmoke; }
 +    #panel:overview .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel:overview .panel-button.clock-display:focus, #panel:overview .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.17); }
 +      #panel:overview .panel-button.clock-display:active, #panel:overview .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.28); }
 +        #panel:overview .panel-button.clock-display:active:hover, #panel:overview .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.32); }
 +      #panel:overview .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel:overview .panel-button.clock-display:focus .clock, #panel:overview .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.17); }
 +      #panel:overview .panel-button.clock-display:active .clock, #panel:overview .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.28); }
 +        #panel:overview .panel-button.clock-display:active .clock:hover, #panel:overview .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.32); }
 +  #panel .panel-status-indicators-box,
 +  #panel .panel-status-menu-box {
 +    spacing: 2px; }
 +  #panel .power-status.panel-status-indicators-box {
 +    spacing: 0; }
 +  #panel .privacy-indicator {
 +    color: #ff7800; }
 +
 +#appMenu {
 +  spacing: 0.409em; }
 +  #appMenu .label-shadow {
 +    color: transparent; }
 +
 +#appMenu .panel-status-menu-box {
 +  padding: 0 0.409em;
 +  spacing: 0.409em; }
 +
 +.clock-display-box {
 +  spacing: 2px; }
 +  .clock-display-box .clock {
 +    padding-left: 0.818em;
 +    padding-right: 0.818em; }
 +
 +/* Activities Ripple */
 +.ripple-box {
 +  background-color: rgba(255, 255, 255, 0.2);
 +  box-shadow: 0 0 2px 2px rgba(255, 255, 255, 0.2);
 +  width: 52px;
 +  height: 52px;
 +  border-radius: 0 0 52px 0; }
 +  .ripple-box:rtl {
 +    border-radius: 0 0 0 52px; }
 +
 +.quick-settings {
 +  padding: 18px;
 +  border-radius: 36px; }
 +  .quick-settings .icon-button, .quick-settings .login-dialog-button.cancel-button, .quick-settings .login-dialog-button.switch-user-button, .quick-settings .login-dialog-button.login-dialog-session-list-button, .quick-settings .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .quick-settings .pager-button, .quick-settings .message .message-header .message-expand-button, .message .message-header .quick-settings .message-expand-button,
 +  .quick-settings .message .message-header .message-close-button,
 +  .message .message-header .quick-settings .message-close-button, .quick-settings .screenshot-ui-show-pointer-button, .quick-settings .button {
 +    padding: 10.5px; }
 +
 +.quick-settings-grid {
 +  spacing-rows: 12px;
 +  spacing-columns: 12px; }
 +
 +.quick-toggle, .quick-menu-toggle {
 +  border-radius: 999px;
 +  min-width: 12em;
 +  max-width: 12em;
 +  min-height: 3.273em;
 +  border: none; }
 +
 +.quick-toggle {
 +  background-color: none;
 +  /* Move padding into the box; this is to allow menu arrows
 +     to extend to the border */ }
 +  .quick-toggle > StBoxLayout {
 +    spacing: 9px; }
 +  .quick-toggle.button {
 +    padding: 0; }
 +  .quick-toggle > StBoxLayout {
 +    padding: 0 12px; }
 +  .quick-toggle:ltr > StBoxLayout {
 +    padding-left: 15px; }
 +  .quick-toggle:rtl > StBoxLayout {
 +    padding-right: 15px; }
 +  .quick-toggle .quick-toggle-title {
 +    font-weight: bold; }
 +  .quick-toggle StBoxLayout > .quick-toggle-subtitle {
 +    font-weight: normal; }
 +  .quick-toggle .quick-toggle-icon {
 +    icon-size: 1.091em; }
 +
 +.quick-menu-toggle .quick-toggle {
 +  min-width: auto;
 +  max-width: auto; }
 +  .quick-menu-toggle .quick-toggle:ltr {
 +    border-radius: 999px 0 0 999px; }
 +  .quick-menu-toggle .quick-toggle:ltr > StBoxLayout {
 +    padding-right: 0.6135em; }
 +  .quick-menu-toggle .quick-toggle:rtl {
 +    border-radius: 0 999px 999px 0; }
 +  .quick-menu-toggle .quick-toggle:rtr > StBoxLayout {
 +    padding-left: 0.6135em; }
 +  .quick-menu-toggle .quick-toggle:ltr:last-child {
 +    border-radius: 999px; }
 +  .quick-menu-toggle .quick-toggle:rtl:last-child {
 +    border-radius: 999px; }
 +
 +.quick-menu-toggle .quick-toggle-arrow {
 +  padding: 0.409em 0.71575em;
 +  border-width: 0;
 +  border-color: rgba(255, 255, 255, 0.25); }
 +  .quick-menu-toggle .quick-toggle-arrow:checked {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4f; }
++    border-color: st-lighten(-st-accent-color, 15%); }
 +  .quick-menu-toggle .quick-toggle-arrow:ltr {
 +    border-radius: 0 999px 999px 0;
 +    border-left-width: 1px; }
 +  .quick-menu-toggle .quick-toggle-arrow:rtl {
 +    border-radius: 999px 0 0 999px;
 +    border-right-width: 1px; }
 +
 +.quick-slider > StBoxLayout {
 +  spacing: 6px; }
 +
 +.quick-slider .icon-button, .quick-slider .login-dialog-button.cancel-button, .quick-slider .login-dialog-button.switch-user-button, .quick-slider .login-dialog-button.login-dialog-session-list-button, .quick-slider .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .quick-slider .pager-button, .quick-slider .message .message-header .message-expand-button, .message .message-header .quick-slider .message-expand-button,
 +.quick-slider .message .message-header .message-close-button,
 +.message .message-header .quick-slider .message-close-button, .quick-slider .screenshot-ui-show-pointer-button {
 +  padding: 6px; }
 +
 +.quick-slider .slider-bin {
 +  padding: 6px;
 +  border-radius: 999px; }
 +  .quick-slider .slider-bin:focus {
 +    color: #ffffff;
-       background-color: #505459; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 9%), 5%); }
 +    .quick-slider .slider-bin:focus:hover {
-     background-color: #474747; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 4%), 5%); }
 +
 +.quick-toggle-menu {
 +  border-radius: 24px;
 +  margin: 12px 18px 0; }
 +  .quick-toggle-menu:insensitive {
 +    color: #ffffff;
-         background-color: #3584e4;
-         color: #ffffff; }
++    background-color: st-mix(#ffffff, #353535, 9%); }
 +  .quick-toggle-menu .popup-menu-item > StIcon {
 +    -st-icon-style: symbolic;
 +    icon-size: 1.091em; }
 +  .quick-toggle-menu .header {
 +    spacing-rows: 3px;
 +    spacing-columns: 12px;
 +    padding-bottom: 12px; }
 +    .quick-toggle-menu .header .icon {
 +      icon-size: 1.6365em;
 +      border-radius: 999px;
 +      padding: 9px;
 +      background-color: rgba(255, 255, 255, 0.2); }
 +      .quick-toggle-menu .header .icon.active {
-     background-color: #474747;
++        background-color: -st-accent-color;
++        color: -st-accent-fg-color; }
 +
 +.quick-settings-system-item > StBoxLayout {
 +  spacing: 12px; }
 +
 +.quick-settings-system-item .power-item {
 +  min-height: 0;
 +  min-width: 0; }
 +  .quick-settings-system-item .power-item:insensitive {
 +    color: #ffffff;
- .controls-manager, .secondary-monitor-workspaces {
++    background-color: st-mix(#ffffff, #353535, 9%);
 +    background-color: transparent; }
 +
 +.nm-network-item .wireless-secure-icon {
 +  icon-size: 0.5455em; }
 +
 +.bt-device-item .popup-menu-icon {
 +  -st-icon-style: symbolic; }
 +
 +.bt-menu-placeholder.popup-menu-item {
 +  text-align: center;
 +  padding: 2em 4em; }
 +
 +.device-subtitle {
 +  color: rgba(255, 255, 255, 0.5); }
 +
 +.keyboard-brightness-level {
 +  spacing: 6px; }
 +
 +.background-apps-quick-toggle {
 +  min-height: 2.728em;
 +  background-color: transparent; }
 +  .background-apps-quick-toggle StIcon {
 +    icon-size: 1.091em !important; }
 +
 +.background-app-item .popup-menu-icon {
 +  icon-size: 32px !important;
 +  -st-icon-style: regular !important; }
 +
 +.background-app-item .icon-button, .background-app-item .login-dialog-button.cancel-button, .background-app-item .login-dialog-button.switch-user-button, .background-app-item .login-dialog-button.login-dialog-session-list-button, .background-app-item .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .background-app-item .pager-button, .background-app-item .message .message-header .message-expand-button, .message .message-header .background-app-item .message-expand-button,
 +.background-app-item .message .message-header .message-close-button,
 +.message .message-header .background-app-item .message-close-button, .background-app-item .screenshot-ui-show-pointer-button {
 +  padding: 6px;
 +  background-color: rgba(255, 255, 255, 0.13); }
 +  .background-app-item .icon-button:hover, .background-app-item .login-dialog-button.cancel-button:hover, .background-app-item .login-dialog-button.switch-user-button:hover, .background-app-item .login-dialog-button.login-dialog-session-list-button:hover, .background-app-item .calendar .calendar-month-header .pager-button:hover, .calendar .calendar-month-header .background-app-item .pager-button:hover, .background-app-item .message .message-header .message-expand-button:hover, .message .message-header .background-app-item .message-expand-button:hover,
 +  .background-app-item .message .message-header .message-close-button:hover,
 +  .message .message-header .background-app-item .message-close-button:hover, .background-app-item .screenshot-ui-show-pointer-button:hover {
 +    background-color: rgba(255, 255, 255, 0.22); }
 +  .background-app-item .icon-button:active, .background-app-item .login-dialog-button.cancel-button:active, .background-app-item .login-dialog-button.switch-user-button:active, .background-app-item .login-dialog-button.login-dialog-session-list-button:active, .background-app-item .calendar .calendar-month-header .pager-button:active, .calendar .calendar-month-header .background-app-item .pager-button:active, .background-app-item .message .message-header .message-expand-button:active, .message .message-header .background-app-item .message-expand-button:active,
 +  .background-app-item .message .message-header .message-close-button:active,
 +  .message .message-header .background-app-item .message-close-button:active, .background-app-item .screenshot-ui-show-pointer-button:active {
 +    background-color: rgba(255, 255, 255, 0.31); }
 +
 +.background-app-item .spinner {
 +  padding: 6px; }
 +
 +.background-app-item.popup-inactive-menu-item {
 +  color: #ffffff; }
 +
 +/* OVERVIEW */
- .overview-controls {
-   padding-bottom: 32px; }
- 
++.secondary-monitor-workspaces {
 +  spacing: 12px; }
 +
 +#overviewGroup {
 +  background-color: #282828; }
 +
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(59, 80, 106, 0.2875); }
 +/* Window Picker */
 +.window-picker {
 +  spacing: 6px; }
 +
 +.window-close, .screenshot-ui-close-button {
 +  background-color: rgba(71, 71, 71, 0.98);
 +  color: whitesmoke;
 +  border-radius: 999px;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
 +  padding: 3px;
 +  height: 32px;
 +  width: 32px;
 +  transition-duration: 100ms;
 +  border: 2px solid transparent; }
 +  .window-close StIcon, .screenshot-ui-close-button StIcon {
 +    icon-size: 24px; }
 +  .window-close:hover, .screenshot-ui-close-button:hover {
 +    background-color: rgba(88, 88, 88, 0.98); }
 +  .window-close:active, .screenshot-ui-close-button:active {
 +    background-color: rgba(104, 104, 104, 0.98); }
 +
 +.workspace-background {
 +  border-radius: 30px;
 +  background-color: rgba(3, 2, 1, 0);
 +  box-shadow: 0 4px 16px 4px rgba(0, 0, 0, 0.2); }
 +
 +.search-entry {
 +  border-radius: 999px;
 +  margin-top: 12px;
 +  margin-bottom: 6px;
 +  width: 24em; }
 +  .search-entry .search-entry-icon {
 +    icon-size: 1.091em;
 +    margin-top: 2px;
 +    padding: 0 4px; }
 +
 +/* Search */
 +#searchResults {
 +  margin: 0 4px; }
 +
 +#searchResultsContent {
 +  max-width: 1044px; }
 +
 +.search-section {
 +  spacing: 18px; }
 +  .search-section .search-section-separator {
 +    height: 8px;
 +    background-color: transparent; }
 +
 +.search-section-content {
 +  background-color: #3d3d3d;
 +  color: whitesmoke;
 +  border-radius: 24px;
 +  padding: 12px;
 +  margin: 0 12px;
 +  border: 2px solid transparent; }
 +
 +.list-search-result, .search-provider-icon {
 +  color: whitesmoke;
 +  background-color: #3d3d3d;
 +  border-radius: 13.2px; }
 +  .list-search-result:focus, .search-provider-icon:focus {
 +    color: whitesmoke;
-       background-color: #4e5256; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(61, 61, 61, 0.25), 5%); }
 +    .list-search-result:focus:hover, .search-provider-icon:focus:hover {
-     background-color: #4f4f4f; }
++      background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 7%), 5%); }
 +  .list-search-result:hover, .search-provider-icon:hover {
 +    color: whitesmoke;
-     background-color: #545454; }
++    background-color: st-lighten(#3d3d3d, 7%); }
 +  .list-search-result:active, .search-provider-icon:active {
 +    color: whitesmoke;
-       background-color: #666666; }
++    background-color: st-lighten(#3d3d3d, 9%); }
 +    .list-search-result:active:hover, .search-provider-icon:active:hover {
-       background-color: #52565b; }
++      background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +    .list-search-result:active:focus, .search-provider-icon:active:focus {
-     background-color: #515151; }
++      background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +  .list-search-result:highlighted, .search-provider-icon:highlighted, .list-search-result:selected, .search-provider-icon:selected, .list-search-result:checked, .search-provider-icon:checked {
 +    color: whitesmoke;
-       background-color: #636363; }
++    background-color: st-lighten(#3d3d3d, 8%); }
 +    .list-search-result:highlighted:hover, .search-provider-icon:highlighted:hover, .list-search-result:selected:hover, .search-provider-icon:selected:hover, .list-search-result:checked:hover, .search-provider-icon:checked:hover {
-       background-color: #686868; }
++      background-color: st-lighten(st-lighten(#3d3d3d, 8%), 7%); }
 +    .list-search-result:highlighted:active, .search-provider-icon:highlighted:active, .list-search-result:selected:active, .search-provider-icon:selected:active, .list-search-result:checked:active, .search-provider-icon:checked:active {
-     color: rgba(245, 245, 245, 0.5);
++      background-color: st-lighten(st-lighten(#3d3d3d, 8%), 9%); }
 +  .list-search-result:insensitive, .search-provider-icon:insensitive {
-     background-color: rgba(53, 132, 228, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++    color: st-transparentize(whitesmoke, 0.5);
 +    background-color: #3d3d3d; }
 +  .list-search-result:drop, .search-provider-icon:drop {
-   margin-top: 12px; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.search-statustext {
 +  color: rgba(245, 245, 245, 0.8); }
 +
 +.grid-search-results {
 +  spacing: 30px; }
 +
 +.search-provider-icon:ltr {
 +  margin-right: 4px; }
 +
 +.search-provider-icon:rtl {
 +  margin-left: 4px; }
 +
 +.search-provider-icon .list-search-provider-content {
 +  spacing: 12px; }
 +  .search-provider-icon .list-search-provider-content .list-search-provider-details {
 +    width: 120px;
 +    color: whitesmoke; }
 +
 +.list-search-results {
 +  spacing: 6px; }
 +
 +.list-search-result .list-search-result-content {
 +  spacing: 6px; }
 +
 +.list-search-result .list-search-result-title {
 +  spacing: 12px; }
 +
 +.list-search-result .list-search-result-description {
 +  color: #959595; }
 +
 +/* Dash */
 +#dash {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-       background-color: rgba(59, 80, 106, 0.2875); }
++  padding-left: 6px;
++  padding-right: 6px; }
 +  #dash .dash-background {
 +    background-color: #3d3d3d;
 +    border-radius: 28px;
 +    padding-top: 12px;
 +    padding-bottom: 12px;
 +    padding-left: 10px;
 +    padding-right: 10px; }
 +  #dash .dash-item-container .placeholder {
 +    background-image: none;
 +    background-size: contain;
 +    height: 32px; }
 +  #dash .dash-item-container .empty-dash-drop-target {
 +    width: 32px;
 +    height: 32px; }
 +  #dash .dash-item-container .show-apps,
 +  #dash .dash-item-container .overview-tile,
 +  #dash .dash-item-container .grid-search-result {
 +    margin: 0 2px;
 +    padding-bottom: 12px; }
 +    #dash .dash-item-container .show-apps .overview-icon,
 +    #dash .dash-item-container .overview-tile .overview-icon,
 +    #dash .dash-item-container .grid-search-result .overview-icon {
 +      color: whitesmoke;
 +      background-color: #3d3d3d; }
 +    #dash .dash-item-container .show-apps:focus .overview-icon,
 +    #dash .dash-item-container .overview-tile:focus .overview-icon,
 +    #dash .dash-item-container .grid-search-result:focus .overview-icon {
 +      color: whitesmoke;
-         background-color: #4e5256; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, rgba(61, 61, 61, 0.25), 5%); }
 +      #dash .dash-item-container .show-apps:focus .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:focus .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:focus .overview-icon:hover {
-       background-color: #4f4f4f; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 7%), 5%); }
 +    #dash .dash-item-container .show-apps:hover .overview-icon,
 +    #dash .dash-item-container .overview-tile:hover .overview-icon,
 +    #dash .dash-item-container .grid-search-result:hover .overview-icon {
 +      color: whitesmoke;
-       background-color: #545454; }
++      background-color: st-lighten(#3d3d3d, 7%); }
 +    #dash .dash-item-container .show-apps:active .overview-icon,
 +    #dash .dash-item-container .overview-tile:active .overview-icon,
 +    #dash .dash-item-container .grid-search-result:active .overview-icon {
 +      color: whitesmoke;
-         background-color: #666666; }
++      background-color: st-lighten(#3d3d3d, 9%); }
 +      #dash .dash-item-container .show-apps:active .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:active .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:active .overview-icon:hover {
-         background-color: #52565b; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +      #dash .dash-item-container .show-apps:active .overview-icon:focus,
 +      #dash .dash-item-container .overview-tile:active .overview-icon:focus,
 +      #dash .dash-item-container .grid-search-result:active .overview-icon:focus {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +    #dash .dash-item-container .show-apps:checked .overview-icon,
 +    #dash .dash-item-container .overview-tile:checked .overview-icon,
 +    #dash .dash-item-container .grid-search-result:checked .overview-icon {
 +      color: whitesmoke;
-         background-color: #636363; }
++      background-color: st-lighten(#3d3d3d, 8%); }
 +      #dash .dash-item-container .show-apps:checked .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:checked .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:checked .overview-icon:hover {
-         background-color: #686868; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 7%); }
 +      #dash .dash-item-container .show-apps:checked .overview-icon:active,
 +      #dash .dash-item-container .overview-tile:checked .overview-icon:active,
 +      #dash .dash-item-container .grid-search-result:checked .overview-icon:active {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(44, 65, 91, 0.2875); }
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 9%); }
 +  #dash .dash-item-container .app-grid-running-dot {
 +    offset-y: -12px; }
 +  #dash .dash-separator {
 +    width: 1px;
 +    margin-left: 4px;
 +    margin-right: 4px;
 +    background-color: rgba(245, 245, 245, 0.1); }
 +  #dash .dash-separator,
 +  #dash .dash-background {
 +    margin-bottom: 12px; }
 +
 +.dash-label {
 +  -y-offset: 8px; }
 +
 +/* App Grid */
 +.icon-grid {
 +  row-spacing: 12px;
 +  column-spacing: 12px;
 +  max-row-spacing: 36px;
 +  max-column-spacing: 36px;
 +  page-padding-top: 24px;
 +  page-padding-bottom: 24px;
 +  page-padding-left: 18px;
 +  page-padding-right: 18px; }
 +
 +/* App Icons */
 +.overview-tile, .grid-search-result {
 +  color: whitesmoke;
 +  background-color: #282828;
 +  border-radius: 24px;
 +  padding: 12px; }
 +  .overview-tile:focus, .grid-search-result:focus {
 +    color: whitesmoke;
-       background-color: #3a3e42; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.25), 5%); }
 +    .overview-tile:focus:hover, .grid-search-result:focus:hover {
-     background-color: #3a3a3a; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 7%), 5%); }
 +  .overview-tile:hover, .grid-search-result:hover {
 +    color: whitesmoke;
-     background-color: #3f3f3f; }
++    background-color: st-lighten(#282828, 7%); }
 +  .overview-tile:active, .grid-search-result:active {
 +    color: whitesmoke;
-       background-color: #515151; }
++    background-color: st-lighten(#282828, 9%); }
 +    .overview-tile:active:hover, .grid-search-result:active:hover {
-       background-color: #3e4247; }
++      background-color: st-lighten(st-lighten(#282828, 9%), 7%); }
 +    .overview-tile:active:focus, .grid-search-result:active:focus {
-     background-color: #3c3c3c; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 9%), 5%); }
 +  .overview-tile:highlighted, .grid-search-result:highlighted, .overview-tile:selected, .grid-search-result:selected, .overview-tile:checked, .grid-search-result:checked {
 +    color: whitesmoke;
-       background-color: #4e4e4e; }
++    background-color: st-lighten(#282828, 8%); }
 +    .overview-tile:highlighted:hover, .grid-search-result:highlighted:hover, .overview-tile:selected:hover, .grid-search-result:selected:hover, .overview-tile:checked:hover, .grid-search-result:checked:hover {
-       background-color: #535353; }
++      background-color: st-lighten(st-lighten(#282828, 8%), 7%); }
 +    .overview-tile:highlighted:active, .grid-search-result:highlighted:active, .overview-tile:selected:active, .grid-search-result:selected:active, .overview-tile:checked:active, .grid-search-result:checked:active {
-     color: rgba(245, 245, 245, 0.5);
++      background-color: st-lighten(st-lighten(#282828, 8%), 9%); }
 +  .overview-tile:insensitive, .grid-search-result:insensitive {
-     background-color: rgba(53, 132, 228, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++    color: st-transparentize(whitesmoke, 0.5);
 +    background-color: #282828; }
 +  .overview-tile:drop, .grid-search-result:drop {
-   background-color: #3a3a3a; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +  .overview-tile .overview-icon.overview-icon-with-label > StBoxLayout, .grid-search-result .overview-icon.overview-icon-with-label > StBoxLayout {
 +    spacing: 6px; }
 +
 +.app-folder {
 +  color: whitesmoke;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #3a3e43; }
++  background-color: st-mix(whitesmoke, #282828, 9%); }
 +  .app-folder:focus {
 +    color: whitesmoke;
-       background-color: #43474c; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(whitesmoke, #282828, 9%), 5%); }
 +    .app-folder:focus:hover {
-     background-color: #444444; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 9%), 4%), 5%); }
 +  .app-folder:hover {
 +    color: whitesmoke;
-     background-color: #515151; }
++    background-color: st-lighten(st-mix(whitesmoke, #282828, 9%), 4%); }
 +  .app-folder:active {
 +    color: whitesmoke;
-       background-color: #5b5b5b; }
++    background-color: st-lighten(st-mix(whitesmoke, #282828, 9%), 9%); }
 +    .app-folder:active:hover {
-       background-color: #505458; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 9%), 9%), 4%); }
 +    .app-folder:active:focus {
-     background-color: #4e4e4e; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 9%), 9%), 5%); }
 +  .app-folder:highlighted, .app-folder:selected, .app-folder:checked {
 +    color: whitesmoke;
-       background-color: #595959; }
++    background-color: st-lighten(st-mix(whitesmoke, #282828, 9%), 8%); }
 +    .app-folder:highlighted:hover, .app-folder:selected:hover, .app-folder:checked:hover {
-       background-color: #656565; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 9%), 8%), 4%); }
 +    .app-folder:highlighted:active, .app-folder:selected:active, .app-folder:checked:active {
-     color: rgba(245, 245, 245, 0.5);
-     background-color: #323232; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 9%), 8%), 9%); }
 +  .app-folder:insensitive {
-     background-color: rgba(53, 132, 228, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++    color: st-transparentize(whitesmoke, 0.5);
++    background-color: st-darken(st-mix(whitesmoke, #282828, 9%), 3%); }
 +  .app-folder:drop {
-     background-color: #4e4e4e; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.app-grid-running-dot {
 +  height: 5px;
 +  width: 5px;
 +  border-radius: 5px;
 +  background-color: whitesmoke;
 +  offset-y: 6px; }
 +
 +.app-folder-dialog-container {
 +  padding-top: 2.2em; }
 +
 +.app-folder-dialog {
 +  width: 720px;
 +  height: 720px;
 +  border-radius: 64px;
 +  background-color: #3d3d3d;
 +  color: whitesmoke;
 +  padding: 0 1px;
 +  box-shadow: inset 0 0 0 1px rgba(245, 245, 245, 0.1); }
 +  .app-folder-dialog .folder-name-container {
 +    padding: 24px 36px;
 +    padding-bottom: 0; }
 +    .app-folder-dialog .folder-name-container .folder-name-entry {
 +      width: 12em; }
 +  .app-folder-dialog .icon-button, .app-folder-dialog .login-dialog-button.cancel-button, .app-folder-dialog .login-dialog-button.switch-user-button, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button, .app-folder-dialog .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .app-folder-dialog .pager-button, .app-folder-dialog .message .message-header .message-expand-button, .message .message-header .app-folder-dialog .message-expand-button,
 +  .app-folder-dialog .message .message-header .message-close-button,
 +  .message .message-header .app-folder-dialog .message-close-button, .app-folder-dialog .screenshot-ui-show-pointer-button {
 +    color: whitesmoke;
-       background-color: #585858; }
++    background-color: st-mix(whitesmoke, #3d3d3d, 9%); }
 +    .app-folder-dialog .icon-button:hover, .app-folder-dialog .login-dialog-button.cancel-button:hover, .app-folder-dialog .login-dialog-button.switch-user-button:hover, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:hover, .app-folder-dialog .calendar .calendar-month-header .pager-button:hover, .calendar .calendar-month-header .app-folder-dialog .pager-button:hover, .app-folder-dialog .message .message-header .message-expand-button:hover, .message .message-header .app-folder-dialog .message-expand-button:hover,
 +    .app-folder-dialog .message .message-header .message-close-button:hover,
 +    .message .message-header .app-folder-dialog .message-close-button:hover, .app-folder-dialog .screenshot-ui-show-pointer-button:hover {
 +      color: whitesmoke;
-       background-color: #656565; }
++      background-color: st-lighten(st-mix(whitesmoke, #3d3d3d, 9%), 4%); }
 +    .app-folder-dialog .icon-button:active, .app-folder-dialog .login-dialog-button.cancel-button:active, .app-folder-dialog .login-dialog-button.switch-user-button:active, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active, .app-folder-dialog .calendar .calendar-month-header .pager-button:active, .calendar .calendar-month-header .app-folder-dialog .pager-button:active, .app-folder-dialog .message .message-header .message-expand-button:active, .message .message-header .app-folder-dialog .message-expand-button:active,
 +    .app-folder-dialog .message .message-header .message-close-button:active,
 +    .message .message-header .app-folder-dialog .message-close-button:active, .app-folder-dialog .screenshot-ui-show-pointer-button:active {
 +      color: whitesmoke;
-         background-color: #6f6f6f; }
++      background-color: st-lighten(st-mix(whitesmoke, #3d3d3d, 9%), 9%); }
 +      .app-folder-dialog .icon-button:active:hover, .app-folder-dialog .login-dialog-button.cancel-button:active:hover, .app-folder-dialog .login-dialog-button.switch-user-button:active:hover, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active:hover, .app-folder-dialog .calendar .calendar-month-header .pager-button:active:hover, .calendar .calendar-month-header .app-folder-dialog .pager-button:active:hover, .app-folder-dialog .message .message-header .message-expand-button:active:hover, .message .message-header .app-folder-dialog .message-expand-button:active:hover,
 +      .app-folder-dialog .message .message-header .message-close-button:active:hover,
 +      .message .message-header .app-folder-dialog .message-close-button:active:hover, .app-folder-dialog .screenshot-ui-show-pointer-button:active:hover {
-         background-color: #63676b; }
++        background-color: st-lighten(st-lighten(st-mix(whitesmoke, #3d3d3d, 9%), 9%), 4%); }
 +      .app-folder-dialog .icon-button:active:focus, .app-folder-dialog .login-dialog-button.cancel-button:active:focus, .app-folder-dialog .login-dialog-button.switch-user-button:active:focus, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active:focus, .app-folder-dialog .calendar .calendar-month-header .pager-button:active:focus, .calendar .calendar-month-header .app-folder-dialog .pager-button:active:focus, .app-folder-dialog .message .message-header .message-expand-button:active:focus, .message .message-header .app-folder-dialog .message-expand-button:active:focus,
 +      .app-folder-dialog .message .message-header .message-close-button:active:focus,
 +      .message .message-header .app-folder-dialog .message-close-button:active:focus, .app-folder-dialog .screenshot-ui-show-pointer-button:active:focus {
-       background-color: #4f4f4f; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #3d3d3d, 9%), 9%), 5%); }
 +  .app-folder-dialog .page-indicators {
 +    margin-bottom: 24px; }
 +  .app-folder-dialog .page-navigation-arrow {
 +    color: whitesmoke;
 +    background-color: #3d3d3d; }
 +    .app-folder-dialog .page-navigation-arrow:hover {
 +      color: whitesmoke;
-       background-color: #545454; }
++      background-color: st-lighten(#3d3d3d, 7%); }
 +    .app-folder-dialog .page-navigation-arrow:active {
 +      color: whitesmoke;
-         background-color: #666666; }
++      background-color: st-lighten(#3d3d3d, 9%); }
 +      .app-folder-dialog .page-navigation-arrow:active:hover {
-         background-color: #52565b; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +      .app-folder-dialog .page-navigation-arrow:active:focus {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-       background-color: rgba(59, 80, 106, 0.2875); }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +  .app-folder-dialog .overview-tile, .app-folder-dialog .grid-search-result {
 +    color: whitesmoke;
 +    background-color: #3d3d3d; }
 +    .app-folder-dialog .overview-tile:focus, .app-folder-dialog .grid-search-result:focus {
 +      color: whitesmoke;
-         background-color: #4e5256; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, rgba(61, 61, 61, 0.25), 5%); }
 +      .app-folder-dialog .overview-tile:focus:hover, .app-folder-dialog .grid-search-result:focus:hover {
-       background-color: #4f4f4f; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 7%), 5%); }
 +    .app-folder-dialog .overview-tile:hover, .app-folder-dialog .grid-search-result:hover {
 +      color: whitesmoke;
-       background-color: #545454; }
++      background-color: st-lighten(#3d3d3d, 7%); }
 +    .app-folder-dialog .overview-tile:active, .app-folder-dialog .grid-search-result:active {
 +      color: whitesmoke;
-         background-color: #666666; }
++      background-color: st-lighten(#3d3d3d, 9%); }
 +      .app-folder-dialog .overview-tile:active:hover, .app-folder-dialog .grid-search-result:active:hover {
-         background-color: #52565b; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +      .app-folder-dialog .overview-tile:active:focus, .app-folder-dialog .grid-search-result:active:focus {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +    .app-folder-dialog .overview-tile:highlighted, .app-folder-dialog .grid-search-result:highlighted, .app-folder-dialog .overview-tile:selected, .app-folder-dialog .grid-search-result:selected, .app-folder-dialog .overview-tile:checked, .app-folder-dialog .grid-search-result:checked {
 +      color: whitesmoke;
-         background-color: #636363; }
++      background-color: st-lighten(#3d3d3d, 8%); }
 +      .app-folder-dialog .overview-tile:highlighted:hover, .app-folder-dialog .grid-search-result:highlighted:hover, .app-folder-dialog .overview-tile:selected:hover, .app-folder-dialog .grid-search-result:selected:hover, .app-folder-dialog .overview-tile:checked:hover, .app-folder-dialog .grid-search-result:checked:hover {
-         background-color: #686868; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 7%); }
 +      .app-folder-dialog .overview-tile:highlighted:active, .app-folder-dialog .grid-search-result:highlighted:active, .app-folder-dialog .overview-tile:selected:active, .app-folder-dialog .grid-search-result:selected:active, .app-folder-dialog .overview-tile:checked:active, .app-folder-dialog .grid-search-result:checked:active {
-       color: rgba(245, 245, 245, 0.5);
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 9%); }
 +    .app-folder-dialog .overview-tile:insensitive, .app-folder-dialog .grid-search-result:insensitive {
-       background-color: rgba(53, 132, 228, 0.2);
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++      color: st-transparentize(whitesmoke, 0.5);
 +      background-color: #3d3d3d; }
 +    .app-folder-dialog .overview-tile:drop, .app-folder-dialog .grid-search-result:drop {
-     background-color: #3a3a3a; }
++      background-color: st-transparentize(-st-accent-color, 0.8);
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.rename-folder-popup .rename-folder-popup-item {
 +  spacing: 6px; }
 +  .rename-folder-popup .rename-folder-popup-item:ltr, .rename-folder-popup .rename-folder-popup-item:rtl {
 +    padding: 0 12px; }
 +
 +.page-indicator {
 +  padding: 6px 12px 0;
 +  transition-duration: 400ms; }
 +  .page-indicator .page-indicator-icon {
 +    width: 10px;
 +    height: 10px;
 +    border-radius: 999px;
 +    background-color: whitesmoke;
 +    transition-duration: 400ms; }
 +
 +.apps-scroll-view {
 +  padding: 0; }
 +
 +.system-action-icon {
 +  background-color: rgba(245, 245, 245, 0.1);
 +  color: whitesmoke;
 +  border-radius: 999px;
 +  icon-size: 48px; }
 +
 +.page-navigation-hint.dnd {
 +  background: rgba(255, 255, 255, 0.1); }
 +
 +.page-navigation-hint.next:ltr, .page-navigation-hint.previous:rtl {
 +  background-gradient-start: rgba(255, 255, 255, 0.05);
 +  background-gradient-end: transparent;
 +  background-gradient-direction: horizontal;
 +  border-radius: 24px 0px 0px 24px; }
 +
 +.page-navigation-hint.previous:ltr, .page-navigation-hint.next:rtl {
 +  background-gradient-start: transparent;
 +  background-gradient-end: rgba(255, 255, 255, 0.05);
 +  background-gradient-direction: horizontal;
 +  border-radius: 0px 24px 24px 0px; }
 +
 +.page-navigation-arrow {
 +  margin: 6px;
 +  padding: 18px;
 +  width: 24px;
 +  height: 24px;
 +  border-radius: 999px;
 +  transition-duration: 100ms;
 +  color: whitesmoke;
 +  background-color: #282828; }
 +  .page-navigation-arrow > StIcon {
 +    color: whitesmoke; }
 +  .page-navigation-arrow:hover {
 +    color: whitesmoke;
-     background-color: #3f3f3f; }
++    background-color: st-lighten(#282828, 7%); }
 +  .page-navigation-arrow:active {
 +    color: whitesmoke;
-       background-color: #515151; }
++    background-color: st-lighten(#282828, 9%); }
 +    .page-navigation-arrow:active:hover {
-       background-color: #3e4247; }
++      background-color: st-lighten(st-lighten(#282828, 9%), 7%); }
 +    .page-navigation-arrow:active:focus {
-   border: 3px solid #3584e4;
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 9%), 5%); }
 +
 +/* Workspace pager */
 +.workspace-thumbnails {
 +  visible-width: 32px;
 +  spacing: 6px;
 +  padding: 6px; }
 +  .workspace-thumbnails .workspace-thumbnail {
 +    color: whitesmoke;
 +    background-color: #4e4e4e;
 +    border-radius: 4px;
 +    border: 1px solid transparent; }
 +  .workspace-thumbnails .placeholder {
 +    background-image: url("resource:///org/gnome/shell/theme/workspace-placeholder.svg");
 +    background-size: contain;
 +    width: 18px; }
 +
 +.workspace-thumbnail-indicator {
-   background-color: rgba(188, 214, 246, 0.3);
-   box-shadow: 0 0 2px 2px #8fbbf0; }
++  border: 3px solid -st-accent-color;
 +  border-radius: 8px; }
 +
 +.ripple-pointer-location {
 +  width: 50px;
 +  height: 50px;
 +  border-radius: 25px;
-   -pie-border-color: #3584e4;
-   -pie-background-color: rgba(233, 242, 252, 0.3); }
++  background-color: st-lighten(st-transparentize(-st-accent-color, 0.7), 30%);
++  box-shadow: 0 0 2px 2px st-lighten(-st-accent-color, 20%); }
 +
 +.pie-timer {
 +  width: 60px;
 +  height: 60px;
 +  -pie-border-width: 3px;
-   border: 2px solid #3584e4; }
++  -pie-border-color: -st-accent-color;
++  -pie-background-color: st-lighten(st-transparentize(-st-accent-color, 0.7), 40%); }
 +
 +.magnifier-zoom-region {
-   background-color: rgba(53, 132, 228, 0.3);
-   border: 1px solid #3584e4; }
++  border: 2px solid -st-accent-color; }
 +  .magnifier-zoom-region.full-screen {
 +    border-width: 0; }
 +
 +.select-area-rubberband {
-   background-color: rgba(53, 132, 228, 0.5);
-   border: 1px solid #3584e4; }
++  background-color: st-transparentize(-st-accent-color, 0.7);
++  border: 1px solid -st-accent-color; }
 +
 +.user-icon {
 +  background-size: contain;
 +  border-radius: 999px;
 +  icon-size: 64px;
 +  background-color: rgba(255, 255, 255, 0.05);
 +  color: #ffffff; }
 +  .user-icon StIcon {
 +    padding: 12px; }
 +  .user-icon.user-avatar {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1); }
 +
 +.lightbox {
 +  background-color: black; }
 +
 +.flashspot {
 +  background-color: white; }
 +
 +.hidden {
 +  color: transparent; }
 +
 +.caps-lock-warning-label {
 +  text-align: center;
 +  padding-bottom: 8px;
 +  color: #f6d32d; }
 +
 +/* Workspace animation */
 +.workspace-animation {
 +  background-color: #353535; }
 +
 +/* Tiled window previews */
 +.tile-preview {
-   background-color: #5d5d5d; }
++  background-color: st-transparentize(-st-accent-color, 0.5);
++  border: 1px solid -st-accent-color; }
 +
 +/* On-screen Keyboard */
 +#keyboard {
 +  background-color: #353535;
 +  box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.02); }
 +  #keyboard .page-indicator {
 +    padding: 6px; }
 +    #keyboard .page-indicator .page-indicator-icon {
 +      width: 8px;
 +      height: 8px; }
 +
 +.key-container {
 +  padding: 4px;
 +  spacing: 4px; }
 +
 +.keyboard-key {
 +  font-size: 1.455em;
 +  font-weight: bold;
 +  min-height: 1.2em;
 +  min-width: 1.2em;
 +  border-width: 1px;
 +  border-style: solid;
 +  border-radius: 10px;
 +  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: #464a4f; }
++  background-color: st-mix(#ffffff, #4d4d4d, 9%); }
 +  .keyboard-key:focus {
 +    color: #ffffff;
-       background-color: #505459; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 9%), 5%); }
 +    .keyboard-key:focus:hover {
-     background-color: #676767; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 4%), 5%); }
 +  .keyboard-key:hover {
 +    color: #ffffff;
-     background-color: #747474; }
++    background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 4%); }
 +  .keyboard-key:active {
 +    color: #ffffff;
-       background-color: #7e7e7e; }
++    background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%); }
 +    .keyboard-key:active:hover {
-       background-color: #71757a; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 4%); }
 +    .keyboard-key:active:focus {
-     background-color: #717171; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 5%); }
 +  .keyboard-key:checked {
 +    color: #ffffff;
-       background-color: #7c7c7c; }
++    background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%); }
 +    .keyboard-key:checked:hover {
-       background-color: #888888; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 4%); }
 +    .keyboard-key:checked:active {
-     background-color: #454545;
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 9%); }
 +  .keyboard-key:grayed {
 +    background-color: #2d2d2d;
 +    color: #ffffff;
 +    border-color: rgba(255, 255, 255, 0.1); }
 +  .keyboard-key.default-key {
 +    color: #ffffff;
-       background-color: #4f4f4f; }
++    background-color: st-mix(#ffffff, #333333, 9%);
 +    border-radius: 10px; }
 +    .keyboard-key.default-key:hover {
 +      color: #ffffff;
-       background-color: #5c5c5c; }
++      background-color: st-lighten(st-mix(#ffffff, #333333, 9%), 4%); }
 +    .keyboard-key.default-key:active {
 +      color: #ffffff;
-         background-color: #666666; }
++      background-color: st-lighten(st-mix(#ffffff, #333333, 9%), 9%); }
 +      .keyboard-key.default-key:active:hover {
-         background-color: #5a5e63; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #333333, 9%), 9%), 4%); }
 +      .keyboard-key.default-key:active:focus {
-       background-color: #595959; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #333333, 9%), 9%), 5%); }
 +    .keyboard-key.default-key:checked {
 +      color: #ffffff;
-         background-color: #646464; }
++      background-color: st-lighten(st-mix(#ffffff, #333333, 9%), 8%); }
 +      .keyboard-key.default-key:checked:hover {
-         background-color: #707070; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #333333, 9%), 8%), 4%); }
 +      .keyboard-key.default-key:checked:active {
-       border-color: #4b92e7;
-       background-color: #3584e4; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #333333, 9%), 8%), 9%); }
 +    .keyboard-key.default-key:latched {
-     color: #ffffff;
-     background-color: #478fe6;
++      border-color: st-lighten(-st-accent-color, 5%);
++      background-color: -st-accent-color; }
 +  .keyboard-key.enter-key {
-       color: #ffffff;
-       background-color: #599ae8; }
++    color: -st-accent-fg-color;
++    background-color: st-mix(-st-accent-fg-color, -st-accent-color, 9%);
 +    border-radius: 10px;
 +    color: #ffffff; }
 +    .keyboard-key.enter-key:hover {
-       color: #ffffff;
-       background-color: #6fa8eb; }
++      color: -st-accent-fg-color;
++      background-color: st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 4%); }
 +    .keyboard-key.enter-key:active {
-         background-color: #81b3ee; }
++      color: -st-accent-fg-color;
++      background-color: st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 9%); }
 +      .keyboard-key.enter-key:active:hover {
-         background-color: #6ca6eb; }
++        background-color: st-lighten(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 9%), 4%); }
 +      .keyboard-key.enter-key:active:focus {
-       color: #ffffff;
-       background-color: #6ba5eb; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 9%), 5%); }
 +    .keyboard-key.enter-key:checked {
-         background-color: #7db0ed; }
++      color: -st-accent-fg-color;
++      background-color: st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 8%); }
 +      .keyboard-key.enter-key:checked:hover {
-         background-color: #93bdf0; }
++        background-color: st-lighten(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 8%), 4%); }
 +      .keyboard-key.enter-key:checked:active {
-     background-color: #5d5d5d;
++        background-color: st-lighten(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 8%), 9%); }
 +  .keyboard-key.shift-key-uppercase {
 +    background-color: gray;
 +    color: #353535; }
 +    .keyboard-key.shift-key-uppercase:hover {
 +      background-color: #8c8c8c;
 +      color: #424242; }
 +  .keyboard-key StIcon {
 +    icon-size: 24px; }
 +
 +.keyboard-subkeys {
 +  -arrow-border-radius: 16px;
 +  -arrow-background-color: #353535;
 +  -arrow-border-width: 1px;
 +  -arrow-border-color: #4c4c4c;
 +  -arrow-base: 20px;
 +  -arrow-rise: 10px;
 +  -boxpointer-gap: 6px;
 +  padding: 6px; }
 +  .keyboard-subkeys .keyboard-key {
 +    color: #ffffff;
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-       background-color: #464a4f; }
++    background-color: st-mix(#ffffff, #4d4d4d, 9%);
 +    border-radius: 10px; }
 +    .keyboard-subkeys .keyboard-key:focus {
 +      color: #ffffff;
-         background-color: #505459; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 9%), 5%); }
 +      .keyboard-subkeys .keyboard-key:focus:hover {
-       background-color: #676767; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 4%), 5%); }
 +    .keyboard-subkeys .keyboard-key:hover {
 +      color: #ffffff;
-       background-color: #747474; }
++      background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 4%); }
 +    .keyboard-subkeys .keyboard-key:active {
 +      color: #ffffff;
-         background-color: #7e7e7e; }
++      background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%); }
 +      .keyboard-subkeys .keyboard-key:active:hover {
-         background-color: #71757a; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 4%); }
 +      .keyboard-subkeys .keyboard-key:active:focus {
-       background-color: #717171; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 5%); }
 +    .keyboard-subkeys .keyboard-key:checked {
 +      color: #ffffff;
-         background-color: #7c7c7c; }
++      background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%); }
 +      .keyboard-subkeys .keyboard-key:checked:hover {
-         background-color: #888888; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 4%); }
 +      .keyboard-subkeys .keyboard-key:checked:active {
-   border-color: #4b92e7;
-   background-color: #3584e4; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 9%); }
 +
 +.emoji-page .keyboard-key {
 +  background-color: transparent;
 +  border: none;
 +  color: initial; }
 +
 +.emoji-panel .keyboard-key:latched {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-       background-color: #464a4f; }
++  border-color: st-lighten(-st-accent-color, 5%);
++  background-color: -st-accent-color; }
 +
 +.word-suggestions {
 +  spacing: 12px;
 +  min-height: 17pt;
 +  padding: 12px;
 +  color: #ffffff; }
 +  .word-suggestions StButton {
 +    margin: 0 3px;
 +    min-width: 32px;
 +    border-radius: 4px;
 +    padding: 0px 18px;
 +    background-color: transparent;
 +    border-color: transparent;
 +    box-shadow: none; }
 +    .word-suggestions StButton:insensitive {
 +      background-color: transparent !important; }
 +    .word-suggestions StButton:focus {
 +      color: #ffffff;
-         background-color: #505459; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 9%), 5%); }
 +      .word-suggestions StButton:focus:hover {
-       background-color: #676767; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 4%), 5%); }
 +    .word-suggestions StButton:hover {
 +      color: #ffffff;
-       background-color: #747474; }
++      background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 4%); }
 +    .word-suggestions StButton:active {
 +      color: #ffffff;
-         background-color: #7e7e7e; }
++      background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%); }
 +      .word-suggestions StButton:active:hover {
-         background-color: #71757a; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 4%); }
 +      .word-suggestions StButton:active:focus {
-       background-color: #717171; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 5%); }
 +    .word-suggestions StButton:checked {
 +      color: #ffffff;
-         background-color: #7c7c7c; }
++      background-color: st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%); }
 +      .word-suggestions StButton:checked:hover {
-         background-color: #888888; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 4%); }
 +      .word-suggestions StButton:checked:active {
-   #LookingGlassDialog StBoxLayout#EvalBox {
-     padding: 4px;
-     spacing: 6px;
-     padding: 6px; }
-   #LookingGlassDialog StBoxLayout#ResultsArea {
-     spacing: 6px;
-     padding: 6px; }
- 
- .lg-dialog StEntry {
-   min-height: 1.5em; }
- 
- .lg-dialog .shell-link {
-   color: #62a0ea; }
-   .lg-dialog .shell-link:hover {
-     color: #8fbbf0; }
-   .lg-dialog .shell-link:active {
-     color: #3585e4; }
- 
- .lg-dialog .actor-link {
-   color: #9a9a9a; }
-   .lg-dialog .actor-link:hover {
-     color: #cdcdcd; }
-   .lg-dialog .actor-link:active {
-     color: #676767; }
-   .lg-dialog .actor-link StIcon {
-     icon-size: 12px; }
- 
- .lg-completions-text {
-   font-style: italic; }
- 
- .lg-obj-inspector-title {
-   spacing: 6px; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 9%); }
 +
 +/* Looking Glass */
++.lg-dialog StEntry {
++  min-height: 1.5em; }
++
++.lg-dialog .shell-link {
++  color: st-lighten(-st-accent-color, 20%); }
++  .lg-dialog .shell-link:hover {
++    color: st-lighten(st-lighten(-st-accent-color, 20%), 10%); }
++  .lg-dialog .shell-link:active {
++    color: st-darken(st-lighten(-st-accent-color, 20%), 10%); }
++
++.lg-dialog .actor-link {
++  color: st-darken(#ffffff, 20%); }
++  .lg-dialog .actor-link:hover {
++    color: #ffffff; }
++  .lg-dialog .actor-link:active {
++    color: st-lighten(#ffffff, 20%); }
++  .lg-dialog .actor-link StIcon {
++    icon-size: 12px; }
++
++.lg-completions-text {
++  font-style: italic; }
++
 +#LookingGlassDialog {
 +  background-color: rgba(53, 53, 53, 0.98);
 +  color: #ffffff;
 +  border-radius: 16px;
 +  margin-top: 4px;
 +  border: 2px solid transparent;
 +  padding: 6px;
 +  spacing: 6px;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2); }
 +  #LookingGlassDialog > #Toolbar {
 +    border: none;
 +    padding: 6px;
 +    border-radius: 0;
 +    background-color: transparent;
 +    spacing: 6px; }
 +    #LookingGlassDialog > #Toolbar .lg-toolbar-button {
 +      padding: 6px 12px; }
 +      #LookingGlassDialog > #Toolbar .lg-toolbar-button > StIcon {
 +        icon-size: 16px; }
 +  #LookingGlassDialog .labels {
 +    spacing: 6px; }
 +  #LookingGlassDialog .notebook-tab {
++    background-color: transparent;
 +    -natural-hpadding: 12px;
 +    -minimum-hpadding: 12px;
 +    padding: 6px 12px; }
- .lg-obj-inspector-button {
++    #LookingGlassDialog .notebook-tab:selected {
++      color: #ffffff;
++      background-color: st-lighten(st-mix(#ffffff, #353535, 9%), 9%); }
++      #LookingGlassDialog .notebook-tab:selected:hover {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 9%), 9%), 4%); }
++      #LookingGlassDialog .notebook-tab:selected:focus {
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 9%), 9%), 5%); }
 +
-   padding: 4px;
-   border-radius: 8px; }
-   .lg-obj-inspector-button:hover {
-     border: 1px solid #ffffff; }
++#LookingGlassPropertyInspector {
++  background-color: #353535;
++  color: #ffffff;
++  border-radius: 16px;
 +  border: 1px solid rgba(255, 255, 255, 0.1);
- #lookingGlassExtensions {
++  padding: 12px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-title {
++    spacing: 4px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button {
++    padding: 6px 12px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-close-button {
++    margin: 4px;
++    padding: 6px;
++    border-radius: 999px; }
++    #LookingGlassPropertyInspector .lg-obj-inspector-close-button > StIcon {
++      icon-size: 16px; }
 +
- .lg-extensions-list {
++#LookingGlassEvaluator {
 +  padding: 6px; }
++  #LookingGlassEvaluator .evaluator-results {
++    spacing: 6px; }
 +
- .lg-extension-meta {
++#LookingGlassWindows {
 +  padding: 6px;
 +  spacing: 6px; }
++  #LookingGlassWindows .lg-window {
++    color: #ffffff;
++    background-color: st-mix(#ffffff, #353535, 9%);
++    margin: 0;
++    padding: 12px; }
 +
- #LookingGlassPropertyInspector {
-   background: #353535;
-   border: 1px solid rgba(255, 255, 255, 0.1);
-   border-radius: 8px;
-   padding: 6px; }
++#LookingGlassExtensions .lg-extensions-list {
++  padding: 6px;
 +  spacing: 6px; }
 +
- .lg-debug-flag-button {
-   color: #ffffff; }
-   .lg-debug-flag-button StLabel {
-     padding: 6px, 12px; }
-   .lg-debug-flag-button:hover {
-     color: white; }
-   .lg-debug-flag-button:active {
-     color: #cccccc; }
++#LookingGlassExtensions .lg-extension {
++  color: #ffffff;
++  background-color: st-mix(#ffffff, #353535, 9%);
++  margin: 0;
++  spacing: 4px;
++  padding: 12px; }
++  #LookingGlassExtensions .lg-extension .lg-extension-name {
++    color: #ffffff !important; }
++  #LookingGlassExtensions .lg-extension .lg-extension-meta {
++    spacing: 12px; }
 +
- .lg-debug-flags-header {
-   padding-top: 12px;
-   padding: 6px; }
++#LookingGlassExtensions .lg-extensions-none {
++  color: rgba(255, 255, 255, 0.5); }
 +
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-     background-color: rgba(44, 65, 91, 0.2875); }
++#LookingGlassActors {
++  padding: 6px;
++  spacing: 4px; }
++
++#LookingGlassDebugFlags .lg-debug-flags-header {
++  padding: 6px;
++  padding-top: 12px; }
++
++#LookingGlassDebugFlags .lg-debug-flag-button {
++  padding: 9px 12px;
++  margin-bottom: 6px; }
++  #LookingGlassDebugFlags .lg-debug-flag-button StLabel {
++    font-weight: normal !important; }
++  #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch {
++    background: rgba(255, 255, 255, 0.15); }
++    #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:hover {
++      background: rgba(255, 255, 255, 0.2); }
++    #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:checked {
++      background: -st-accent-color;
++      color: -st-accent-fg-color; }
++      #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:checked:hover {
++        background-color: st-lighten(-st-accent-color, 5%);
++        color: st-lighten(-st-accent-fg-color, 5%); }
 +
 +.login-dialog,
 +.unlock-dialog {
 +  color: whitesmoke; }
 +  .login-dialog .caps-lock-warning-label,
 +  .login-dialog .login-dialog-message-warning,
 +  .unlock-dialog .caps-lock-warning-label,
 +  .unlock-dialog .login-dialog-message-warning {
 +    color: whitesmoke; }
 +  .login-dialog .login-dialog-prompt-layout,
 +  .unlock-dialog .login-dialog-prompt-layout {
 +    width: 25em;
 +    spacing: 9px; }
 +
 +.login-dialog-button.cancel-button {
 +  padding: 9px; }
 +
 +.login-dialog-button-box {
 +  spacing: 12px; }
 +
 +.conflicting-session-dialog-content {
 +  spacing: 20px; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-title {
 +    text-align: center;
 +    margin-bottom: 5px; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-desc {
 +    text-align: center; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-desc-warning {
 +    text-align: center;
 +    color: #f6d32d; }
 +
 +.login-dialog-logo-bin {
 +  margin: 3em 0; }
 +
 +.login-dialog-banner-view {
 +  max-width: 25em; }
 +  .login-dialog-banner-view .login-dialog-banner {
 +    color: gainsboro; }
 +
 +.login-dialog-message {
 +  text-align: center; }
 +
 +.login-dialog-message-hint, .login-dialog-message {
 +  color: gainsboro;
 +  min-height: 2.75em; }
 +
 +.login-dialog-user-selection-box {
 +  padding-top: 4em;
 +  padding-bottom: 8em; }
 +
 +.login-dialog-not-listed-label {
 +  padding: 6px; }
 +
 +.login-dialog-not-listed-button {
 +  color: whitesmoke;
 +  background-color: #282828;
 +  padding: 0 6px;
 +  margin: 6px; }
 +  .login-dialog-not-listed-button:focus {
 +    color: whitesmoke;
-       background-color: #3a3e42; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.25), 5%); }
 +    .login-dialog-not-listed-button:focus:hover {
-     background-color: #3a3a3a; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 7%), 5%); }
 +  .login-dialog-not-listed-button:hover {
 +    color: whitesmoke;
-     background-color: #3f3f3f; }
++    background-color: st-lighten(#282828, 7%); }
 +  .login-dialog-not-listed-button:active {
 +    color: whitesmoke;
-       background-color: #515151; }
++    background-color: st-lighten(#282828, 9%); }
 +    .login-dialog-not-listed-button:active:hover {
-       background-color: #3e4247; }
++      background-color: st-lighten(st-lighten(#282828, 9%), 7%); }
 +    .login-dialog-not-listed-button:active:focus {
-     background-color: #3584e4;
-     color: #ffffff; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 9%), 5%); }
 +
 +.login-dialog-auth-list-view {
 +  -st-vfade-offset: 3em; }
 +
 +.login-dialog-auth-list {
 +  spacing: 6px;
 +  margin-left: 2em; }
 +
 +.login-dialog-auth-list-title {
 +  margin-left: 2em; }
 +
 +.login-dialog-auth-list-item {
 +  border-radius: 16px;
 +  padding: 4px;
 +  color: darkgray; }
 +  .login-dialog-auth-list-item:focus, .login-dialog-auth-list-item:selected {
-       background-color: #3a3a3a;
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +
 +.login-dialog-auth-list-label:ltr {
 +  padding-left: 15px;
 +  text-align: left; }
 +
 +.login-dialog-auth-list-label:rtl {
 +  padding-right: 15px;
 +  text-align: right; }
 +
 +.login-dialog-user-list-view {
 +  width: 25em;
 +  -st-vfade-offset: 3em; }
 +  .login-dialog-user-list-view .login-dialog-user-list {
 +    margin: 0 8px;
 +    spacing: 12px; }
 +    .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item {
 +      color: whitesmoke;
-         box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.5) !important;
-         background-color: #3a3e43; }
++      background-color: st-mix(whitesmoke, #282828, 9%);
 +      border-radius: 16px;
 +      padding: 9px; }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:selected, .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:focus {
 +        color: whitesmoke;
-           background-color: #43474c; }
++        box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++        background-color: st-mix(-st-accent-color, st-mix(whitesmoke, #282828, 9%), 5%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:selected:hover, .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:focus:hover {
-         background-color: #444444; }
++          background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 9%), 4%), 5%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:hover {
 +        color: whitesmoke;
-         background-color: #515151; }
++        background-color: st-lighten(st-mix(whitesmoke, #282828, 9%), 4%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active {
 +        color: whitesmoke;
-           background-color: #5b5b5b; }
++        background-color: st-lighten(st-mix(whitesmoke, #282828, 9%), 9%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active:hover {
-           background-color: #505458; }
++          background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 9%), 9%), 4%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active:focus {
-         border-color: #3584e4; }
++          background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 9%), 9%), 5%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item .user-icon {
 +        border: 2px solid transparent; }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item .login-dialog-timed-login-indicator {
 +        height: 2px;
 +        margin-top: 6px;
 +        background-color: rgba(245, 245, 245, 0.7); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:logged-in .user-icon {
-           background-color: rgba(53, 132, 228, 0.3); }
++        border-color: -st-accent-color; }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:logged-in .user-icon StIcon {
-     font-weight: 200; }
++          background-color: st-transparentize(-st-accent-color, 0.7); }
 +
 +.unlock-dialog {
 +  background-color: transparent; }
 +
 +.screen-shield-background {
 +  background: black;
 +  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6); }
 +
 +#lockDialogGroup {
 +  background-color: #282828; }
 +
 +.unlock-dialog-clock {
 +  color: whitesmoke;
 +  spacing: 2em; }
 +  .unlock-dialog-clock .unlock-dialog-clock-time {
 +    font-size: 6.546em;
-     background-color: rgba(53, 132, 228, 0.5); }
++    font-weight: 800; }
 +  .unlock-dialog-clock .unlock-dialog-clock-date {
 +    font-weight: 400; }
 +  .unlock-dialog-clock .unlock-dialog-clock-hint {
 +    margin-top: 2em;
 +    padding: 6px 18px;
 +    border-radius: 16px;
 +    font-weight: bold; }
 +
 +#unlockDialogNotifications StButton#vhandle, #unlockDialogNotifications StButton#hhandle {
 +  background-color: rgba(53, 53, 53, 0.3); }
 +  #unlockDialogNotifications StButton#vhandle:hover, #unlockDialogNotifications StButton#vhandle:focus, #unlockDialogNotifications StButton#hhandle:hover, #unlockDialogNotifications StButton#hhandle:focus {
 +    background-color: rgba(53, 53, 53, 0.5); }
 +  #unlockDialogNotifications StButton#vhandle:active, #unlockDialogNotifications StButton#hhandle:active {
-       padding: 24px; }
++    background-color: st-transparentize(-st-accent-color, 0.5); }
 +
 +.unlock-dialog-notifications-container {
 +  margin: 12px;
 +  spacing: 6px;
 +  width: 25em;
 +  background-color: transparent; }
 +  .unlock-dialog-notifications-container .summary-notification-stack-scrollview {
 +    padding-top: 0;
 +    padding-bottom: 0; }
 +  .unlock-dialog-notifications-container .notification,
 +  .unlock-dialog-notifications-container .unlock-dialog-notification-source {
 +    padding: 12px 16px;
 +    border: none;
 +    background-color: rgba(245, 245, 245, 0.1);
 +    color: whitesmoke;
 +    border-radius: 16px; }
 +    .unlock-dialog-notifications-container .notification.critical,
 +    .unlock-dialog-notifications-container .unlock-dialog-notification-source.critical {
 +      background-color: rgba(245, 245, 245, 0.2); }
 +
 +.unlock-dialog-notification-icon {
 +  icon-size: 32px; }
 +
 +.unlock-dialog-notification-label {
 +  padding-left: 12px;
 +  padding-right: 0; }
 +  .unlock-dialog-notification-label:rtl {
 +    padding-right: 12px;
 +    padding-left: 0; }
 +
 +.unlock-dialog-notification-count-text {
 +  font-weight: bold;
 +  padding: 0 12px;
 +  color: whitesmoke;
 +  background-color: rgba(245, 245, 245, 0.1);
 +  border-radius: 999px; }
 +
 +.login-dialog .user-widget .user-widget-label,
 +.unlock-dialog .user-widget .user-widget-label {
 +  color: whitesmoke; }
 +
 +.login-dialog .user-widget .user-icon,
 +.unlock-dialog .user-widget .user-icon {
 +  background-color: rgba(245, 245, 245, 0.13);
 +  color: whitesmoke; }
 +
 +.login-dialog .user-widget.horizontal,
 +.unlock-dialog .user-widget.horizontal {
 +  spacing: 18px; }
 +
 +.login-dialog .user-widget.vertical,
 +.unlock-dialog .user-widget.vertical {
 +  spacing: 24px; }
 +  .login-dialog .user-widget.vertical .user-widget-label,
 +  .unlock-dialog .user-widget.vertical .user-widget-label {
++    font-weight: 400;
++    font-size: 1.818em;
 +    text-align: center;
 +    margin-bottom: .75em; }
 +  .login-dialog .user-widget.vertical .user-icon,
 +  .unlock-dialog .user-widget.vertical .user-icon {
 +    icon-size: 160px; }
 +    .login-dialog .user-widget.vertical .user-icon StIcon,
 +    .unlock-dialog .user-widget.vertical .user-icon StIcon {
++      padding: 30px; }
index beb4da94a59ddce60ef87d6cfda501bf0ccbc301,0000000000000000000000000000000000000000..53bf66a3ca04cc3dcb46e3650d268c0a2913e000
mode 100644,000000..100644
--- /dev/null
@@@ -1,3419 -1,0 +1,3541 @@@
- .unlock-dialog .screenshot-ui-show-pointer-button, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button, #LookingGlassDialog .notebook-tab, #LookingGlassDialog > #Toolbar .lg-toolbar-button, .icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .message .message-header .message-expand-button,
 +/* This stylesheet is generated, DO NOT EDIT */
 +/* Copyright 2009, 2015 Red Hat, Inc.
 + *
 + * Portions adapted from Mx's data/style/default.css
 + *   Copyright 2009 Intel Corporation
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms and conditions of the GNU Lesser General Public License,
 + * version 2.1, as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope it will be useful, but WITHOUT ANY
 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 + * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 + * more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +/* Global Values */
 +stage {
 +  font-size: 1em;
 +  color: #ffffff; }
 +
 +/* Common Stylings */
 +#dash .dash-item-container .show-apps,
 +#dash .dash-item-container .overview-tile,
 +#dash .dash-item-container .grid-search-result {
 +  background: none;
 +  box-shadow: none;
 +  border: none;
 +  border-radius: 0;
 +  padding: 0;
 +  margin: 0; }
 +
 +.app-folder-dialog .overview-tile, .app-folder-dialog .grid-search-result, .app-folder, .overview-tile, .grid-search-result, #dash .dash-item-container .show-apps .overview-icon,
 +#dash .dash-item-container .overview-tile .overview-icon,
 +#dash .dash-item-container .grid-search-result .overview-icon, .list-search-result, .search-provider-icon, .switcher-list .item-box {
 +  border-radius: 16px;
 +  padding: 6px;
 +  spacing: 6px;
 +  text-align: center;
 +  transition-duration: 100ms; }
 +
 +.login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item, .login-dialog-not-listed-button, .unlock-dialog .button,
 +.unlock-dialog .icon-button,
 +.unlock-dialog .message .message-header .message-expand-button,
 +.message .message-header .unlock-dialog .message-expand-button,
 +.unlock-dialog .message .message-header .message-close-button,
 +.message .message-header .unlock-dialog .message-close-button,
-   background-color: #494949; }
++.unlock-dialog .screenshot-ui-show-pointer-button, #LookingGlassDialog .notebook-tab, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button, #LookingGlassDebugFlags .lg-debug-flag-button, #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++#LookingGlassPropertyInspector .lg-obj-inspector-button, #LookingGlassDialog > #Toolbar .lg-toolbar-button, .icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button, .button {
 +  border-radius: 8px;
 +  padding: 3px 24px;
 +  font-weight: bold;
 +  transition: border-width 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); }
 +
 +.icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .screenshot-ui-show-pointer-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button, .button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #484c51; }
++  background-color: st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%); }
 +  .icon-button:focus, .login-dialog-button.cancel-button:focus, .login-dialog-button.switch-user-button:focus, .login-dialog-button.login-dialog-session-list-button:focus, .screenshot-ui-show-pointer-button:focus, .message .message-header .message-expand-button:focus,
 +  .message .message-header .message-close-button:focus, .calendar .calendar-month-header .pager-button:focus, .button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #515559; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%), 5%); }
 +    .icon-button:focus:hover, .login-dialog-button.cancel-button:focus:hover, .login-dialog-button.switch-user-button:focus:hover, .login-dialog-button.login-dialog-session-list-button:focus:hover, .screenshot-ui-show-pointer-button:focus:hover, .message .message-header .message-expand-button:focus:hover,
 +    .message .message-header .message-close-button:focus:hover, .calendar .calendar-month-header .pager-button:focus:hover, .button:focus:hover {
-     background-color: #525252; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 4%), #ffffff, 87%), 5%); }
 +  .icon-button:hover, .login-dialog-button.cancel-button:hover, .login-dialog-button.switch-user-button:hover, .login-dialog-button.login-dialog-session-list-button:hover, .screenshot-ui-show-pointer-button:hover, .message .message-header .message-expand-button:hover,
 +  .message .message-header .message-close-button:hover, .calendar .calendar-month-header .pager-button:hover, .button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #262626;
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 4%), #ffffff, 87%); }
 +  .icon-button:insensitive, .login-dialog-button.cancel-button:insensitive, .login-dialog-button.switch-user-button:insensitive, .login-dialog-button.login-dialog-session-list-button:insensitive, .screenshot-ui-show-pointer-button:insensitive, .message .message-header .message-expand-button:insensitive,
 +  .message .message-header .message-close-button:insensitive, .calendar .calendar-month-header .pager-button:insensitive, .button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: #5d5d5d; }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #1a1a1a, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .icon-button:selected, .login-dialog-button.cancel-button:selected, .login-dialog-button.switch-user-button:selected, .login-dialog-button.login-dialog-session-list-button:selected, .screenshot-ui-show-pointer-button:selected, .message .message-header .message-expand-button:selected,
 +  .message .message-header .message-close-button:selected, .calendar .calendar-month-header .pager-button:selected, .button:selected, .icon-button:active, .login-dialog-button.cancel-button:active, .login-dialog-button.switch-user-button:active, .login-dialog-button.login-dialog-session-list-button:active, .screenshot-ui-show-pointer-button:active, .message .message-header .message-expand-button:active,
 +  .message .message-header .message-close-button:active, .calendar .calendar-month-header .pager-button:active, .button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #4f4f4f; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 9%), #ffffff, 87%); }
 +    .icon-button:selected:hover, .login-dialog-button.cancel-button:selected:hover, .login-dialog-button.switch-user-button:selected:hover, .login-dialog-button.login-dialog-session-list-button:selected:hover, .screenshot-ui-show-pointer-button:selected:hover, .message .message-header .message-expand-button:selected:hover,
 +    .message .message-header .message-close-button:selected:hover, .calendar .calendar-month-header .pager-button:selected:hover, .button:selected:hover, .icon-button:active:hover, .login-dialog-button.cancel-button:active:hover, .login-dialog-button.switch-user-button:active:hover, .login-dialog-button.login-dialog-session-list-button:active:hover, .screenshot-ui-show-pointer-button:active:hover, .message .message-header .message-expand-button:active:hover,
 +    .message .message-header .message-close-button:active:hover, .calendar .calendar-month-header .pager-button:active:hover, .button:active:hover {
-       background-color: #5b5f64; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 9%), 4%); }
 +    .icon-button:selected:focus, .login-dialog-button.cancel-button:selected:focus, .login-dialog-button.switch-user-button:selected:focus, .login-dialog-button.login-dialog-session-list-button:selected:focus, .screenshot-ui-show-pointer-button:selected:focus, .message .message-header .message-expand-button:selected:focus,
 +    .message .message-header .message-close-button:selected:focus, .calendar .calendar-month-header .pager-button:selected:focus, .button:selected:focus, .icon-button:active:focus, .login-dialog-button.cancel-button:active:focus, .login-dialog-button.switch-user-button:active:focus, .login-dialog-button.login-dialog-session-list-button:active:focus, .screenshot-ui-show-pointer-button:active:focus, .message .message-header .message-expand-button:active:focus,
 +    .message .message-header .message-close-button:active:focus, .calendar .calendar-month-header .pager-button:active:focus, .button:active:focus {
-     background-color: #5b5b5b; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 9%), #ffffff, 87%), 5%); }
 +  .icon-button:checked, .login-dialog-button.cancel-button:checked, .login-dialog-button.switch-user-button:checked, .login-dialog-button.login-dialog-session-list-button:checked, .screenshot-ui-show-pointer-button:checked, .message .message-header .message-expand-button:checked,
 +  .message .message-header .message-close-button:checked, .calendar .calendar-month-header .pager-button:checked, .button:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #4d4d4d; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), #ffffff, 87%); }
 +    .icon-button:checked:hover, .login-dialog-button.cancel-button:checked:hover, .login-dialog-button.switch-user-button:checked:hover, .login-dialog-button.login-dialog-session-list-button:checked:hover, .screenshot-ui-show-pointer-button:checked:hover, .message .message-header .message-expand-button:checked:hover,
 +    .message .message-header .message-close-button:checked:hover, .calendar .calendar-month-header .pager-button:checked:hover, .button:checked:hover {
-       background-color: #595959; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 4%); }
 +    .icon-button:checked:active, .login-dialog-button.cancel-button:checked:active, .login-dialog-button.switch-user-button:checked:active, .login-dialog-button.login-dialog-session-list-button:checked:active, .screenshot-ui-show-pointer-button:checked:active, .message .message-header .message-expand-button:checked:active,
 +    .message .message-header .message-close-button:checked:active, .calendar .calendar-month-header .pager-button:checked:active, .button:checked:active {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(33, 54, 80, 0.2875); }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 9%); }
 +
 +.calendar .calendar-day-heading, .calendar .calendar-day, .calendar .calendar-month-header .calendar-month-label, .icon-button.flat, .flat.login-dialog-button.cancel-button, .flat.login-dialog-button.switch-user-button, .flat.login-dialog-button.login-dialog-session-list-button, .flat.screenshot-ui-show-pointer-button, .message .message-header .flat.message-expand-button,
 +.message .message-header .flat.message-close-button, .calendar .calendar-month-header .pager-button, .button.flat {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
 +  background-color: #1a1a1a;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none; }
 +  .calendar .calendar-day-heading:focus, .calendar .calendar-day:focus, .calendar .calendar-month-header .calendar-month-label:focus, .icon-button.flat:focus, .flat.login-dialog-button.cancel-button:focus, .flat.login-dialog-button.switch-user-button:focus, .flat.login-dialog-button.login-dialog-session-list-button:focus, .flat.screenshot-ui-show-pointer-button:focus, .message .message-header .flat.message-expand-button:focus,
 +  .message .message-header .flat.message-close-button:focus, .calendar .calendar-month-header .pager-button:focus, .button.flat:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #464a4f; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, rgba(26, 26, 26, 0.25), 5%); }
 +    .calendar .calendar-day-heading:focus:hover, .calendar .calendar-day:focus:hover, .calendar .calendar-month-header .calendar-month-label:focus:hover, .icon-button.flat:focus:hover, .flat.login-dialog-button.cancel-button:focus:hover, .flat.login-dialog-button.switch-user-button:focus:hover, .flat.login-dialog-button.login-dialog-session-list-button:focus:hover, .flat.screenshot-ui-show-pointer-button:focus:hover, .message .message-header .flat.message-expand-button:focus:hover,
 +    .message .message-header .flat.message-close-button:focus:hover, .calendar .calendar-month-header .pager-button:focus:hover, .button.flat:focus:hover {
-     background-color: #474747; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#1a1a1a, 7%), #ffffff, 87%), 5%); }
 +  .calendar .calendar-day-heading:hover, .calendar .calendar-day:hover, .calendar .calendar-month-header .calendar-month-label:hover, .icon-button.flat:hover, .flat.login-dialog-button.cancel-button:hover, .flat.login-dialog-button.switch-user-button:hover, .flat.login-dialog-button.login-dialog-session-list-button:hover, .flat.screenshot-ui-show-pointer-button:hover, .message .message-header .flat.message-expand-button:hover,
 +  .message .message-header .flat.message-close-button:hover, .calendar .calendar-month-header .pager-button:hover, .button.flat:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
++    background-color: st-mix(st-lighten(#1a1a1a, 7%), #ffffff, 87%); }
 +  .calendar .calendar-day-heading:insensitive, .calendar .calendar-day:insensitive, .calendar .calendar-month-header .calendar-month-label:insensitive, .icon-button.flat:insensitive, .flat.login-dialog-button.cancel-button:insensitive, .flat.login-dialog-button.switch-user-button:insensitive, .flat.login-dialog-button.login-dialog-session-list-button:insensitive, .flat.screenshot-ui-show-pointer-button:insensitive, .message .message-header .flat.message-expand-button:insensitive,
 +  .message .message-header .flat.message-close-button:insensitive, .calendar .calendar-month-header .pager-button:insensitive, .button.flat:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: #4b4b4b; }
++    color: st-transparentize(#ffffff, 0.5);
 +    background-color: #1a1a1a;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .calendar .calendar-day-heading:selected, .calendar .calendar-day:selected, .calendar .calendar-month-header .calendar-month-label:selected, .icon-button.flat:selected, .flat.login-dialog-button.cancel-button:selected, .flat.login-dialog-button.switch-user-button:selected, .flat.login-dialog-button.login-dialog-session-list-button:selected, .flat.screenshot-ui-show-pointer-button:selected, .message .message-header .flat.message-expand-button:selected,
 +  .message .message-header .flat.message-close-button:selected, .calendar .calendar-month-header .pager-button:selected, .button.flat:selected, .calendar .calendar-day-heading:active, .calendar .calendar-day:active, .calendar .calendar-month-header .calendar-month-label:active, .icon-button.flat:active, .flat.login-dialog-button.cancel-button:active, .flat.login-dialog-button.switch-user-button:active, .flat.login-dialog-button.login-dialog-session-list-button:active, .flat.screenshot-ui-show-pointer-button:active, .message .message-header .flat.message-expand-button:active,
 +  .message .message-header .flat.message-close-button:active, .calendar .calendar-month-header .pager-button:active, .button.flat:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #424242; }
++    background-color: st-mix(st-lighten(#1a1a1a, 9%), #ffffff, 87%); }
 +    .calendar .calendar-day-heading:selected:hover, .calendar .calendar-day:selected:hover, .calendar .calendar-month-header .calendar-month-label:selected:hover, .icon-button.flat:selected:hover, .flat.login-dialog-button.cancel-button:selected:hover, .flat.login-dialog-button.switch-user-button:selected:hover, .flat.login-dialog-button.login-dialog-session-list-button:selected:hover, .flat.screenshot-ui-show-pointer-button:selected:hover, .message .message-header .flat.message-expand-button:selected:hover,
 +    .message .message-header .flat.message-close-button:selected:hover, .calendar .calendar-month-header .pager-button:selected:hover, .button.flat:selected:hover, .calendar .calendar-day-heading:active:hover, .calendar .calendar-day:active:hover, .calendar .calendar-month-header .calendar-month-label:active:hover, .icon-button.flat:active:hover, .flat.login-dialog-button.cancel-button:active:hover, .flat.login-dialog-button.switch-user-button:active:hover, .flat.login-dialog-button.login-dialog-session-list-button:active:hover, .flat.screenshot-ui-show-pointer-button:active:hover, .message .message-header .flat.message-expand-button:active:hover,
 +    .message .message-header .flat.message-close-button:active:hover, .calendar .calendar-month-header .pager-button:active:hover, .button.flat:active:hover {
-       background-color: #4a4e53; }
++      background-color: st-lighten(st-lighten(#1a1a1a, 9%), 7%); }
 +    .calendar .calendar-day-heading:selected:focus, .calendar .calendar-day:selected:focus, .calendar .calendar-month-header .calendar-month-label:selected:focus, .icon-button.flat:selected:focus, .flat.login-dialog-button.cancel-button:selected:focus, .flat.login-dialog-button.switch-user-button:selected:focus, .flat.login-dialog-button.login-dialog-session-list-button:selected:focus, .flat.screenshot-ui-show-pointer-button:selected:focus, .message .message-header .flat.message-expand-button:selected:focus,
 +    .message .message-header .flat.message-close-button:selected:focus, .calendar .calendar-month-header .pager-button:selected:focus, .button.flat:selected:focus, .calendar .calendar-day-heading:active:focus, .calendar .calendar-day:active:focus, .calendar .calendar-month-header .calendar-month-label:active:focus, .icon-button.flat:active:focus, .flat.login-dialog-button.cancel-button:active:focus, .flat.login-dialog-button.switch-user-button:active:focus, .flat.login-dialog-button.login-dialog-session-list-button:active:focus, .flat.screenshot-ui-show-pointer-button:active:focus, .message .message-header .flat.message-expand-button:active:focus,
 +    .message .message-header .flat.message-close-button:active:focus, .calendar .calendar-month-header .pager-button:active:focus, .button.flat:active:focus {
-     background-color: #494949; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#1a1a1a, 9%), #ffffff, 87%), 5%); }
 +  .calendar .calendar-day-heading:checked, .calendar .calendar-day:checked, .calendar .calendar-month-header .calendar-month-label:checked, .icon-button.flat:checked, .flat.login-dialog-button.cancel-button:checked, .flat.login-dialog-button.switch-user-button:checked, .flat.login-dialog-button.login-dialog-session-list-button:checked, .flat.screenshot-ui-show-pointer-button:checked, .message .message-header .flat.message-expand-button:checked,
 +  .message .message-header .flat.message-close-button:checked, .calendar .calendar-month-header .pager-button:checked, .button.flat:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #404040; }
++    background-color: st-mix(st-lighten(#1a1a1a, 8%), #ffffff, 87%); }
 +    .calendar .calendar-day-heading:checked:hover, .calendar .calendar-day:checked:hover, .calendar .calendar-month-header .calendar-month-label:checked:hover, .icon-button.flat:checked:hover, .flat.login-dialog-button.cancel-button:checked:hover, .flat.login-dialog-button.switch-user-button:checked:hover, .flat.login-dialog-button.login-dialog-session-list-button:checked:hover, .flat.screenshot-ui-show-pointer-button:checked:hover, .message .message-header .flat.message-expand-button:checked:hover,
 +    .message .message-header .flat.message-close-button:checked:hover, .calendar .calendar-month-header .pager-button:checked:hover, .button.flat:checked:hover {
-       background-color: #454545; }
++      background-color: st-lighten(st-lighten(#1a1a1a, 8%), 7%); }
 +    .calendar .calendar-day-heading:checked:active, .calendar .calendar-day:checked:active, .calendar .calendar-month-header .calendar-month-label:checked:active, .icon-button.flat:checked:active, .flat.login-dialog-button.cancel-button:checked:active, .flat.login-dialog-button.switch-user-button:checked:active, .flat.login-dialog-button.login-dialog-session-list-button:checked:active, .flat.screenshot-ui-show-pointer-button:checked:active, .message .message-header .flat.message-expand-button:checked:active,
 +    .message .message-header .flat.message-close-button:checked:active, .calendar .calendar-month-header .pager-button:checked:active, .button.flat:checked:active {
-   color: #ffffff;
-   background-color: #4f94e8; }
++      background-color: st-lighten(st-lighten(#1a1a1a, 8%), 9%); }
 +
 +.keyboard-brightness-level .button:checked, .quick-menu-toggle .quick-toggle-arrow:checked, .quick-toggle:checked, .calendar .calendar-day.calendar-today, .icon-button.default, .default.login-dialog-button.cancel-button, .default.login-dialog-button.switch-user-button, .default.login-dialog-button.login-dialog-session-list-button, .default.screenshot-ui-show-pointer-button, .message .message-header .default.message-expand-button,
 +.message .message-header .default.message-close-button, .calendar .calendar-month-header .default.pager-button, .button.default {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none;
-     color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     box-shadow: inset 0 0 0 2px #bcd6f6 !important;
-     background-color: #4e93e8; }
++  color: -st-accent-fg-color;
++  background-color: st-mix(-st-accent-color, #ffffff, 87%); }
 +  .keyboard-brightness-level .button:focus:checked, .quick-menu-toggle .quick-toggle-arrow:focus:checked, .quick-toggle:focus:checked, .calendar .calendar-day.calendar-today:focus, .icon-button.default:focus, .default.login-dialog-button.cancel-button:focus, .default.login-dialog-button.switch-user-button:focus, .default.login-dialog-button.login-dialog-session-list-button:focus, .default.screenshot-ui-show-pointer-button:focus, .message .message-header .default.message-expand-button:focus,
 +  .message .message-header .default.message-close-button:focus, .calendar .calendar-month-header .default.pager-button:focus, .button.default:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none;
-       background-color: #5d9dea; }
++    color: -st-accent-fg-color;
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    box-shadow: inset 0 0 0 2px st-lighten(-st-accent-color, 30%) !important;
++    background-color: st-mix(-st-accent-color, st-mix(-st-accent-color, #ffffff, 87%), 5%); }
 +    .keyboard-brightness-level .button:focus:hover:checked, .quick-menu-toggle .quick-toggle-arrow:focus:hover:checked, .quick-toggle:focus:hover:checked, .calendar .calendar-day.calendar-today:focus:hover, .icon-button.default:focus:hover, .default.login-dialog-button.cancel-button:focus:hover, .default.login-dialog-button.switch-user-button:focus:hover, .default.login-dialog-button.login-dialog-session-list-button:focus:hover, .default.screenshot-ui-show-pointer-button:focus:hover, .message .message-header .default.message-expand-button:focus:hover,
 +    .message .message-header .default.message-close-button:focus:hover, .calendar .calendar-month-header .default.pager-button:focus:hover, .button.default:focus:hover {
-     color: #ffffff;
-     background-color: #5f9eea; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(-st-accent-color, 4%), #ffffff, 87%), 5%); }
 +  .keyboard-brightness-level .button:hover:checked, .quick-menu-toggle .quick-toggle-arrow:hover:checked, .quick-toggle:hover:checked, .calendar .calendar-day.calendar-today:hover, .icon-button.default:hover, .default.login-dialog-button.cancel-button:hover, .default.login-dialog-button.switch-user-button:hover, .default.login-dialog-button.login-dialog-session-list-button:hover, .default.screenshot-ui-show-pointer-button:hover, .message .message-header .default.message-expand-button:hover,
 +  .message .message-header .default.message-close-button:hover, .calendar .calendar-month-header .default.pager-button:hover, .button.default:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #287ce2;
++    color: -st-accent-fg-color;
++    background-color: st-mix(st-lighten(-st-accent-color, 4%), #ffffff, 87%); }
 +  .keyboard-brightness-level .button:insensitive:checked, .quick-menu-toggle .quick-toggle-arrow:insensitive:checked, .quick-toggle:insensitive:checked, .calendar .calendar-day.calendar-today:insensitive, .icon-button.default:insensitive, .default.login-dialog-button.cancel-button:insensitive, .default.login-dialog-button.switch-user-button:insensitive, .default.login-dialog-button.login-dialog-session-list-button:insensitive, .default.screenshot-ui-show-pointer-button:insensitive, .message .message-header .default.message-expand-button:insensitive,
 +  .message .message-header .default.message-close-button:insensitive, .calendar .calendar-month-header .default.pager-button:insensitive, .button.default:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none;
-     color: #ffffff;
-     background-color: #72a9ec; }
++    color: st-transparentize(-st-accent-fg-color, 0.5);
++    background-color: st-darken(-st-accent-color, 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .keyboard-brightness-level .button:active:checked, .quick-menu-toggle .quick-toggle-arrow:active:checked, .quick-toggle:active:checked, .calendar .calendar-day.calendar-today:active, .icon-button.default:active, .default.login-dialog-button.cancel-button:active, .default.login-dialog-button.switch-user-button:active, .default.login-dialog-button.login-dialog-session-list-button:active, .default.screenshot-ui-show-pointer-button:active, .message .message-header .default.message-expand-button:active,
 +  .message .message-header .default.message-close-button:active, .calendar .calendar-month-header .default.pager-button:active, .button.default:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none;
-       background-color: #6fa8ec; }
++    color: -st-accent-fg-color;
++    background-color: st-mix(st-lighten(-st-accent-color, 9%), #ffffff, 87%); }
 +    .keyboard-brightness-level .button:active:hover:checked, .quick-menu-toggle .quick-toggle-arrow:active:hover:checked, .quick-toggle:active:hover:checked, .calendar .calendar-day.calendar-today:active:hover, .icon-button.default:active:hover, .default.login-dialog-button.cancel-button:active:hover, .default.login-dialog-button.switch-user-button:active:hover, .default.login-dialog-button.login-dialog-session-list-button:active:hover, .default.screenshot-ui-show-pointer-button:active:hover, .message .message-header .default.message-expand-button:active:hover,
 +    .message .message-header .default.message-close-button:active:hover, .calendar .calendar-month-header .default.pager-button:active:hover, .button.default:active:hover {
-       background-color: #6fa7ec; }
++      background-color: st-lighten(st-lighten(-st-accent-color, 9%), 4%); }
 +    .keyboard-brightness-level .button:active:focus:checked, .quick-menu-toggle .quick-toggle-arrow:active:focus:checked, .quick-toggle:active:focus:checked, .calendar .calendar-day.calendar-today:active:focus, .icon-button.default:active:focus, .default.login-dialog-button.cancel-button:active:focus, .default.login-dialog-button.switch-user-button:active:focus, .default.login-dialog-button.login-dialog-session-list-button:active:focus, .default.screenshot-ui-show-pointer-button:active:focus, .message .message-header .default.message-expand-button:active:focus,
 +    .message .message-header .default.message-close-button:active:focus, .calendar .calendar-month-header .default.pager-button:active:focus, .button.default:active:focus {
- .calendar, .datemenu-today-button, .lg-extension, .quick-toggle-menu, .message, .events-button,
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(-st-accent-color, 9%), #ffffff, 87%), 5%); }
 +
 +.popup-sub-menu .popup-menu-item, .popup-menu-item {
 +  font-weight: normal;
 +  spacing: 6px;
 +  transition-duration: 100ms;
 +  padding: 9px 12px; }
 +
- .lg-extension, .quick-toggle-menu, .message, .events-button,
++#LookingGlassExtensions .lg-extension, #LookingGlassWindows .lg-window, .calendar, .datemenu-today-button, .quick-toggle-menu, .message, .events-button,
 +.world-clocks-button,
 +.weather-button {
 +  border-radius: 12px;
 +  padding: 0.818em;
 +  margin: 4px;
 +  background-color: #1a1a1a;
 +  box-shadow: 0 1px 2px 0 transparent;
 +  border: 1px solid #1a1a1a;
 +  border-color: transparent;
 +  box-shadow: none; }
 +
-   background-color: #373737; }
-   .lg-extension:hover, .quick-toggle-menu:hover, .message:hover, .events-button:hover,
++.quick-toggle-menu, .message, .events-button,
 +.world-clocks-button,
 +.weather-button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     background-color: #404040; }
-   .lg-extension:active, .quick-toggle-menu:active, .message:active, .events-button:active,
++  background-color: st-mix(#1a1a1a, #ffffff, 87%); }
++  .quick-toggle-menu:hover, .message:hover, .events-button:hover,
 +  .world-clocks-button:hover,
 +  .weather-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #4b4b4b; }
-     .lg-extension:active:hover, .quick-toggle-menu:active:hover, .message:active:hover, .events-button:active:hover,
++    background-color: st-mix(st-lighten(#1a1a1a, 4%), #ffffff, 87%); }
++  .quick-toggle-menu:active, .message:active, .events-button:active,
 +  .world-clocks-button:active,
 +  .weather-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #3b3b3b; }
-     .lg-extension:active:focus, .quick-toggle-menu:active:focus, .message:active:focus, .events-button:active:focus,
++    background-color: st-mix(st-lighten(#1a1a1a, 9%), #ffffff, 87%); }
++    .quick-toggle-menu:active:hover, .message:active:hover, .events-button:active:hover,
 +    .world-clocks-button:active:hover,
 +    .weather-button:active:hover {
-       background-color: #4a4e53; }
-   .lg-extension:focus, .quick-toggle-menu:focus, .message:focus, .events-button:focus,
++      background-color: st-lighten(st-lighten(#1a1a1a, 9%), 4%); }
++    .quick-toggle-menu:active:focus, .message:active:focus, .events-button:active:focus,
 +    .world-clocks-button:active:focus,
 +    .weather-button:active:focus {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #373b40; }
-     .lg-extension:focus:hover, .quick-toggle-menu:focus:hover, .message:focus:hover, .events-button:focus:hover,
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#1a1a1a, 9%), #ffffff, 87%), 5%); }
++  .quick-toggle-menu:focus, .message:focus, .events-button:focus,
 +  .world-clocks-button:focus,
 +  .weather-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #3f4348; }
-   .lg-extension:insensitive, .quick-toggle-menu:insensitive, .message:insensitive, .events-button:insensitive,
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#1a1a1a, #ffffff, 87%), 5%); }
++    .quick-toggle-menu:focus:hover, .message:focus:hover, .events-button:focus:hover,
 +    .world-clocks-button:focus:hover,
 +    .weather-button:focus:hover {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #121212;
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#1a1a1a, 4%), #ffffff, 87%), 5%); }
++  .quick-toggle-menu:insensitive, .message:insensitive, .events-button:insensitive,
 +  .world-clocks-button:insensitive,
 +  .weather-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: #474747; }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(#1a1a1a, 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +
 +.calendar, .datemenu-today-button {
 +  border: 1px solid transparent !important;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  background-color: transparent;
 +  border-color: transparent;
 +  box-shadow: none; }
 +  .calendar:insensitive, .datemenu-today-button:insensitive {
 +    background-color: transparent !important; }
 +  .calendar:hover, .datemenu-today-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #4b4b4b; }
++    background-color: st-mix(st-lighten(#1a1a1a, 7%), #ffffff, 87%); }
 +  .calendar:active, .datemenu-today-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #424242; }
++    background-color: st-mix(st-lighten(#1a1a1a, 9%), #ffffff, 87%); }
 +    .calendar:active:hover, .datemenu-today-button:active:hover {
-       background-color: #4a4e53; }
++      background-color: st-lighten(st-lighten(#1a1a1a, 9%), 7%); }
 +    .calendar:active:focus, .datemenu-today-button:active:focus {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #373b40; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#1a1a1a, 9%), #ffffff, 87%), 5%); }
 +  .calendar:focus, .datemenu-today-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #3f4348; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#1a1a1a, #ffffff, 87%), 5%); }
 +    .calendar:focus:hover, .datemenu-today-button:focus:hover {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #121212;
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#1a1a1a, 4%), #ffffff, 87%), 5%); }
 +  .calendar:insensitive, .datemenu-today-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-   selection-background-color: #3584e4;
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(#1a1a1a, 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +
 +.unlock-dialog .login-dialog-prompt-entry, .login-dialog .login-dialog-prompt-entry, .app-folder-dialog .folder-name-container .folder-name-entry, .search-entry, .lg-dialog StEntry, StEntry {
 +  border-radius: 8px;
 +  padding: 9px 9px;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #2e3237;
++  selection-background-color: st-transparentize(-st-accent-color, 0.7);
 +  selected-color: #ffffff; }
 +
 +StEntry {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  background-color: #2e2e2e;
 +  color: rgba(255, 255, 255, 0.7); }
 +  StEntry:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: #383838;
 +    color: #ffffff; }
 +  StEntry:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
- .modal-dialog .modal-dialog-linked-button, .notification-button {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, #2e2e2e, 5%);
 +    color: #ffffff; }
 +  StEntry:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: #262626;
 +    color: rgba(255, 255, 255, 0.5); }
 +  StEntry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
-   font-weight: bold !important;
++.notification-button, .message .message-header .message-expand-button,
++.message .message-header .message-close-button {
++  font-weight: bold;
++  padding: 6px 12px;
++  border-radius: 8px;
++  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++  color: #ffffff;
++  background-color: st-mix(rgba(255, 255, 255, 0.15), #ffffff, 87%); }
++  .notification-button:focus, .message .message-header .message-expand-button:focus,
++  .message .message-header .message-close-button:focus {
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    color: #ffffff;
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.15), #ffffff, 87%), 5%); }
++    .notification-button:focus:hover, .message .message-header .message-expand-button:focus:hover,
++    .message .message-header .message-close-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.3), #ffffff, 87%), 5%); }
++  .notification-button:hover, .message .message-header .message-expand-button:hover,
++  .message .message-header .message-close-button:hover {
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    color: #ffffff;
++    background-color: st-mix(rgba(255, 255, 255, 0.3), #ffffff, 87%); }
++  .notification-button:active, .message .message-header .message-expand-button:active,
++  .message .message-header .message-close-button:active {
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    color: #ffffff;
++    background-color: st-mix(rgba(255, 255, 255, 0.2), #ffffff, 87%); }
++    .notification-button:active:hover, .message .message-header .message-expand-button:active:hover,
++    .message .message-header .message-close-button:active:hover {
++      background-color: rgba(255, 255, 255, 0.2); }
++    .notification-button:active:focus, .message .message-header .message-expand-button:active:focus,
++    .message .message-header .message-close-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.2), #ffffff, 87%), 5%); }
++  .notification-button:checked, .message .message-header .message-expand-button:checked,
++  .message .message-header .message-close-button:checked {
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    color: #ffffff;
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), #ffffff, 87%); }
++    .notification-button:checked:hover, .message .message-header .message-expand-button:checked:hover,
++    .message .message-header .message-close-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 4%); }
++    .notification-button:checked:active, .message .message-header .message-expand-button:checked:active,
++    .message .message-header .message-close-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 9%); }
++  .notification-button:insensitive, .message .message-header .message-expand-button:insensitive,
++  .message .message-header .message-close-button:insensitive {
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: rgba(255, 255, 255, 0.1);
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    box-shadow: none;
++    border: none; }
++
++.modal-dialog .modal-dialog-linked-button {
++  font-weight: bold;
 +  padding: 12px;
-   background-color: rgba(255, 255, 255, 0.217); }
-   .modal-dialog .modal-dialog-linked-button:ltr, .notification-button:ltr {
-     margin-right: 1px; }
-   .modal-dialog .modal-dialog-linked-button:rtl, .notification-button:rtl {
-     margin-left: 1px; }
-   .modal-dialog .modal-dialog-linked-button:focus, .notification-button:focus {
++  border-radius: 12px;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(194, 218, 247, 0.25615); }
-     .modal-dialog .modal-dialog-linked-button:focus:hover, .notification-button:focus:hover {
-       background-color: rgba(199, 221, 248, 0.280945); }
-   .modal-dialog .modal-dialog-linked-button:hover, .notification-button:hover {
++  background-color: st-mix(rgba(255, 255, 255, 0.1), #ffffff, 87%); }
++  .modal-dialog .modal-dialog-linked-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: rgba(255, 255, 255, 0.2431); }
-   .modal-dialog .modal-dialog-linked-button:active, .notification-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.1), #ffffff, 87%), 5%); }
++    .modal-dialog .modal-dialog-linked-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.13), #ffffff, 87%), 5%); }
++  .modal-dialog .modal-dialog-linked-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: rgba(255, 255, 255, 0.2692); }
-     .modal-dialog .modal-dialog-linked-button:active:hover, .notification-button:active:hover {
++    background-color: st-mix(rgba(255, 255, 255, 0.13), #ffffff, 87%); }
++  .modal-dialog .modal-dialog-linked-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     .modal-dialog .modal-dialog-linked-button:active:focus, .notification-button:active:focus {
-       background-color: rgba(204, 224, 248, 0.30574); }
-   .modal-dialog .modal-dialog-linked-button:checked, .notification-button:checked {
++    background-color: st-mix(rgba(255, 255, 255, 0.16), #ffffff, 87%); }
++    .modal-dialog .modal-dialog-linked-button:active:hover {
 +      background-color: rgba(255, 255, 255, 0.19); }
-     background-color: #5b5b5b; }
-     .modal-dialog .modal-dialog-linked-button:checked:hover, .notification-button:checked:hover {
-       background-color: #4d4d4d; }
-     .modal-dialog .modal-dialog-linked-button:checked:active, .notification-button:checked:active {
-       background-color: #595959; }
-   .modal-dialog .modal-dialog-linked-button:insensitive, .notification-button:insensitive {
++    .modal-dialog .modal-dialog-linked-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.16), #ffffff, 87%), 5%); }
++  .modal-dialog .modal-dialog-linked-button:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #262626;
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), #ffffff, 87%); }
++    .modal-dialog .modal-dialog-linked-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 4%); }
++    .modal-dialog .modal-dialog-linked-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 9%); }
++  .modal-dialog .modal-dialog-linked-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-   .modal-dialog .modal-dialog-linked-button:first-child:ltr, .notification-button:first-child:ltr {
-     border-radius: 0 0 0 15px; }
-   .modal-dialog .modal-dialog-linked-button:last-child:ltr, .notification-button:last-child:ltr {
-     border-radius: 0 0 15px;
-     margin-right: 0 !important; }
-   .modal-dialog .modal-dialog-linked-button:first-child:rtl, .notification-button:first-child:rtl {
-     border-radius: 0 0 15px; }
-   .modal-dialog .modal-dialog-linked-button:last-child:rtl, .notification-button:last-child:rtl {
-     border-radius: 0 0 0 15px;
-     margin-left: 0 !important; }
-   .modal-dialog .modal-dialog-linked-button:first-child:last-child, .notification-button:first-child:last-child {
-     border-radius: 0 0 15px 15px;
-     margin-left: 0 !important;
-     margin-right: 0 !important; }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #1a1a1a, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
- .login-dialog .user-widget.vertical .user-widget-label,
- .unlock-dialog .user-widget.vertical .user-widget-label, .unlock-dialog-clock .unlock-dialog-clock-date, .app-folder-dialog .folder-name-container .folder-name-label, .app-folder-dialog .folder-name-container .folder-name-entry, .search-statustext {
 +
 +.dash-label, .window-caption, .screenshot-ui-tooltip {
 +  background-color: rgba(0, 0, 0, 0.9);
 +  border: 1px solid rgba(255, 255, 255, 0.1);
 +  color: #ffffff;
 +  border-radius: 999px;
 +  padding: 6px 12px;
 +  text-align: center;
 +  background-color: black;
 +  border-color: rgba(255, 255, 255, 0.4); }
 +
 +/* General Typography */
- .conflicting-session-dialog-content .conflicting-session-dialog-title, .lg-debug-flags-header, .message-dialog-content .message-dialog-title, .message-list .message-list-placeholder, .datemenu-today-button .date-label {
++.unlock-dialog-clock .unlock-dialog-clock-date, .app-folder-dialog .folder-name-container .folder-name-label, .app-folder-dialog .folder-name-container .folder-name-entry, .search-statustext {
 +  font-weight: 800;
 +  font-size: 1.818em; }
 +
- .login-dialog-auth-list-label, .word-suggestions, .bt-menu-placeholder.popup-menu-item, .message-dialog-content .message-dialog-title.lightweight, .headline {
++.conflicting-session-dialog-content .conflicting-session-dialog-title, .message-dialog-content .message-dialog-title, .message-list .message-list-placeholder, .datemenu-today-button .date-label {
 +  font-weight: 800;
 +  font-size: 1.364em; }
 +
 +.login-dialog .user-widget.horizontal .user-widget-label,
 +.unlock-dialog .user-widget.horizontal .user-widget-label, .quick-toggle-menu .header .title {
 +  font-weight: 700;
 +  font-size: 1.364em; }
 +
- .login-dialog-not-listed-label, .lg-extension-name, .background-app-item .title, .osd-window, .dialog-list .dialog-list-title, .message-list-controls, .weather-button .weather-box .weather-header-box .weather-header, .world-clocks-button .world-clocks-header, .events-button .events-box .events-list .event-box .event-summary, .events-button .events-box .events-title, .calendar .calendar-month-header .calendar-month-label {
++.login-dialog-auth-list-label, #LookingGlassDebugFlags .lg-debug-flags-header, #LookingGlassExtensions .lg-extensions-none, .word-suggestions, .bt-menu-placeholder.popup-menu-item, .message-dialog-content .message-dialog-title.lightweight, .headline {
 +  font-weight: 700;
 +  font-size: 1.182em; }
 +
- #EvalBox {
++.login-dialog-not-listed-label, #LookingGlassExtensions .lg-extension .lg-extension-name, #LookingGlassWindows .lg-window .lg-window-name, #LookingGlassPropertyInspector .lg-obj-inspector-title, .background-app-item .title, .osd-window, .dialog-list .dialog-list-title, .message-list-controls, .weather-button .weather-box .weather-header-box .weather-header, .world-clocks-button .world-clocks-header, .events-button .events-box .events-list .event-box .event-summary, .events-button .events-box .events-title, .calendar .calendar-month-header .calendar-month-label {
 +  font-weight: 700;
 +  font-size: 1em; }
 +
 +.quick-toggle-menu .header .subtitle, .app-menu .popup-inactive-menu-item:first-child > StLabel {
 +  font-weight: 700;
 +  font-size: 0.818em; }
 +
 +.lg-completions-text, .caps-lock-warning-label, .background-app-item .subtitle, .quick-toggle StBoxLayout > .quick-toggle-subtitle, .screenshot-ui-type-button .icon-label-button-container, .prompt-dialog-error-label,
 +.prompt-dialog-info-label,
 +.prompt-dialog-null-label, .run-dialog .run-dialog-description, .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-description, .message .message-header .message-header-content .event-time, .world-clocks-button .world-clocks-grid .world-clocks-timezone, .events-button .events-box .events-list .event-box .event-time {
 +  font-weight: 400;
 +  font-size: 0.818em; }
 +
 +.weather-button .weather-box .weather-grid .weather-forecast-time, .calendar .calendar-week-number, .calendar .calendar-day-heading, .calendar .calendar-day {
 +  font-weight: 400;
 +  font-size: 0.818em; }
 +
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #191c21;
++#LookingGlassDebugFlags .lg-debug-flag-button StLabel, #LookingGlassEvaluator .evaluator-results, .lg-dialog .actor-link {
 +  font-family: monospace; }
 +
 +.unlock-dialog-clock .unlock-dialog-clock-time, #panel, .weather-button .weather-box .weather-grid .weather-forecast-temp, .world-clocks-button .world-clocks-grid .world-clocks-timezone, .world-clocks-button .world-clocks-grid .world-clocks-time, .events-button .events-box .events-list .event-box .event-time, .calendar .calendar-day-heading, .calendar .calendar-day {
 +  font-feature-settings: "tnum"; }
 +
 +/* OSD Elements */
 +#LookingGlassDialog, .screenshot-ui-panel, .workspace-switcher, .switcher-list, .resize-popup, .osd-window {
 +  color: #ffffff;
 +  background-color: #000000;
 +  border: 1px solid rgba(255, 255, 255, 0.2);
 +  border-radius: 999px;
 +  padding: 12px;
 +  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.4);
 +  border: 2px solid rgba(255, 255, 255, 0.4);
 +  box-shadow: none; }
 +
 +.lg-dialog StEntry {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  background-color: #171717;
 +  color: rgba(255, 255, 255, 0.7); }
 +  .lg-dialog StEntry:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: #212121;
 +    color: #ffffff; }
 +  .lg-dialog StEntry:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
- #LookingGlassDialog .notebook-tab, #LookingGlassDialog > #Toolbar .lg-toolbar-button {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, #171717, 5%);
 +    color: #ffffff; }
 +  .lg-dialog StEntry:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: #0f0f0f;
 +    color: rgba(255, 255, 255, 0.5); }
 +  .lg-dialog StEntry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
-   background-color: #353535; }
-   #LookingGlassDialog .notebook-tab:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus {
++#LookingGlassDebugFlags .lg-debug-flag-button, #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++#LookingGlassPropertyInspector .lg-obj-inspector-button, #LookingGlassDialog > #Toolbar .lg-toolbar-button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #35393e; }
-     #LookingGlassDialog .notebook-tab:focus:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus:hover {
-       background-color: #3e4246; }
-   #LookingGlassDialog .notebook-tab:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:hover {
++  background-color: st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:focus, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:focus,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #3e3e3e; }
-   #LookingGlassDialog .notebook-tab:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%), 5%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:focus:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:focus:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:focus:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 4%), #ffffff, 87%), 5%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:hover,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #494949; }
-     #LookingGlassDialog .notebook-tab:active:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:hover {
-       background-color: #383838; }
-     #LookingGlassDialog .notebook-tab:active:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:focus {
-       background-color: #484c51; }
-   #LookingGlassDialog .notebook-tab:checked, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked {
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 4%), #ffffff, 87%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:active, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #474747; }
-     #LookingGlassDialog .notebook-tab:checked:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:hover {
-       background-color: #363636; }
-     #LookingGlassDialog .notebook-tab:checked:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:active {
-       background-color: #424242; }
-   #LookingGlassDialog .notebook-tab:insensitive, #LookingGlassDialog > #Toolbar .lg-toolbar-button:insensitive {
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:active:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:active:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), 4%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:active:focus, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active:focus,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:active:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%), 5%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:checked, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:checked, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #0f0f0f;
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 8%), #ffffff, 87%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:checked:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:checked:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 8%), 4%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:checked:active, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked:active,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:checked:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 8%), 9%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:insensitive, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:insensitive,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:insensitive, #LookingGlassDialog > #Toolbar .lg-toolbar-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
- .screenshot-ui-show-pointer-button, .screenshot-ui-type-button {
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #000000, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +
-   .screenshot-ui-show-pointer-button:focus, .screenshot-ui-type-button:focus {
++#LookingGlassDialog .notebook-tab, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
 +  background-color: #000000;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none; }
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(14, 36, 61, 0.2875); }
-     .screenshot-ui-show-pointer-button:focus:hover, .screenshot-ui-type-button:focus:hover {
-       background-color: #31353a; }
-   .screenshot-ui-show-pointer-button:hover, .screenshot-ui-type-button:hover {
++  #LookingGlassDialog .notebook-tab:focus, .screenshot-ui-show-pointer-button:focus, .screenshot-ui-type-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #313131; }
-   .screenshot-ui-show-pointer-button:active, .screenshot-ui-type-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, rgba(0, 0, 0, 0.25), 5%); }
++    #LookingGlassDialog .notebook-tab:focus:hover, .screenshot-ui-show-pointer-button:focus:hover, .screenshot-ui-type-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 7%), #ffffff, 87%), 5%); }
++  #LookingGlassDialog .notebook-tab:hover, .screenshot-ui-show-pointer-button:hover, .screenshot-ui-type-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #353535; }
-     .screenshot-ui-show-pointer-button:active:hover, .screenshot-ui-type-button:active:hover {
-       background-color: #292929; }
-     .screenshot-ui-show-pointer-button:active:focus, .screenshot-ui-type-button:active:focus {
-       background-color: #35393e; }
-   .screenshot-ui-show-pointer-button:checked, .screenshot-ui-type-button:checked {
++    background-color: st-mix(st-lighten(#000000, 7%), #ffffff, 87%); }
++  #LookingGlassDialog .notebook-tab:active, .screenshot-ui-show-pointer-button:active, .screenshot-ui-type-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #333333; }
-     .screenshot-ui-show-pointer-button:checked:hover, .screenshot-ui-type-button:checked:hover {
-       background-color: #262626; }
-     .screenshot-ui-show-pointer-button:checked:active, .screenshot-ui-type-button:checked:active {
-       background-color: #2b2b2b; }
-   .screenshot-ui-show-pointer-button:insensitive, .screenshot-ui-type-button:insensitive {
++    background-color: st-mix(st-lighten(#000000, 9%), #ffffff, 87%); }
++    #LookingGlassDialog .notebook-tab:active:hover, .screenshot-ui-show-pointer-button:active:hover, .screenshot-ui-type-button:active:hover {
++      background-color: st-lighten(st-lighten(#000000, 9%), 7%); }
++    #LookingGlassDialog .notebook-tab:active:focus, .screenshot-ui-show-pointer-button:active:focus, .screenshot-ui-type-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 9%), #ffffff, 87%), 5%); }
++  #LookingGlassDialog .notebook-tab:checked, .screenshot-ui-show-pointer-button:checked, .screenshot-ui-type-button:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
++    background-color: st-mix(st-lighten(#000000, 8%), #ffffff, 87%); }
++    #LookingGlassDialog .notebook-tab:checked:hover, .screenshot-ui-show-pointer-button:checked:hover, .screenshot-ui-type-button:checked:hover {
++      background-color: st-lighten(st-lighten(#000000, 8%), 7%); }
++    #LookingGlassDialog .notebook-tab:checked:active, .screenshot-ui-show-pointer-button:checked:active, .screenshot-ui-type-button:checked:active {
++      background-color: st-lighten(st-lighten(#000000, 8%), 9%); }
++  #LookingGlassDialog .notebook-tab:insensitive, .screenshot-ui-show-pointer-button:insensitive, .screenshot-ui-type-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #24282d;
++    color: st-transparentize(#ffffff, 0.5);
 +    background-color: #000000;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +
 +/* System Elements */
 +.login-dialog .login-dialog-prompt-entry, .app-folder-dialog .folder-name-container .folder-name-entry, .search-entry {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  background-color: #232323;
 +  color: rgba(255, 255, 255, 0.7); }
 +  .login-dialog .login-dialog-prompt-entry:hover, .app-folder-dialog .folder-name-container .folder-name-entry:hover, .search-entry:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: #2d2d2d;
 +    color: #ffffff; }
 +  .login-dialog .login-dialog-prompt-entry:focus, .app-folder-dialog .folder-name-container .folder-name-entry:focus, .search-entry:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-   background-color: #404040; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, #232323, 5%);
 +    color: #ffffff; }
 +  .login-dialog .login-dialog-prompt-entry:insensitive, .app-folder-dialog .folder-name-container .folder-name-entry:insensitive, .search-entry:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: #1b1b1b;
 +    color: rgba(255, 255, 255, 0.5); }
 +  .login-dialog .login-dialog-prompt-entry StLabel.hint-text, .app-folder-dialog .folder-name-container .folder-name-entry StLabel.hint-text, .search-entry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
 +.login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #1b1b1b;
++  background-color: st-mix(st-mix(#ffffff, #0d0d0d, 9%), #ffffff, 87%); }
 +  .login-dialog-button.cancel-button:insensitive, .login-dialog-button.switch-user-button:insensitive, .login-dialog-button.login-dialog-session-list-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #3f4348; }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #0d0d0d, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .login-dialog-button.cancel-button:focus, .login-dialog-button.switch-user-button:focus, .login-dialog-button.login-dialog-session-list-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #474b50; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #0d0d0d, 9%), #ffffff, 87%), 5%); }
 +    .login-dialog-button.cancel-button:focus:hover, .login-dialog-button.switch-user-button:focus:hover, .login-dialog-button.login-dialog-session-list-button:focus:hover {
-     background-color: #484848; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 4%), #ffffff, 87%), 5%); }
 +  .login-dialog-button.cancel-button:hover, .login-dialog-button.switch-user-button:hover, .login-dialog-button.login-dialog-session-list-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #545454; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 4%), #ffffff, 87%); }
 +  .login-dialog-button.cancel-button:active, .login-dialog-button.switch-user-button:active, .login-dialog-button.login-dialog-session-list-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #444444; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 9%), #ffffff, 87%); }
 +    .login-dialog-button.cancel-button:active:hover, .login-dialog-button.switch-user-button:active:hover, .login-dialog-button.login-dialog-session-list-button:active:hover {
-       background-color: #52565b; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 9%), 4%); }
 +    .login-dialog-button.cancel-button:active:focus, .login-dialog-button.switch-user-button:active:focus, .login-dialog-button.login-dialog-session-list-button:active:focus {
-     background-color: #515151; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 9%), #ffffff, 87%), 5%); }
 +  .login-dialog-button.cancel-button:checked, .login-dialog-button.switch-user-button:checked, .login-dialog-button.login-dialog-session-list-button:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #424242; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 8%), #ffffff, 87%); }
 +    .login-dialog-button.cancel-button:checked:hover, .login-dialog-button.switch-user-button:checked:hover, .login-dialog-button.login-dialog-session-list-button:checked:hover {
-       background-color: #4e4e4e; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 8%), 4%); }
 +    .login-dialog-button.cancel-button:checked:active, .login-dialog-button.switch-user-button:checked:active, .login-dialog-button.login-dialog-session-list-button:checked:active {
-   background-color: rgba(255, 255, 255, 0.217); }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #0d0d0d, 9%), 8%), 9%); }
 +
 +/* Lockscreen Elements */
 +.unlock-dialog .button,
 +.unlock-dialog .icon-button,
 +.unlock-dialog .calendar .calendar-month-header .pager-button,
 +.calendar .calendar-month-header .unlock-dialog .pager-button,
 +.unlock-dialog .message .message-header .message-expand-button,
 +.message .message-header .unlock-dialog .message-expand-button,
 +.unlock-dialog .message .message-header .message-close-button,
 +.message .message-header .unlock-dialog .message-close-button,
 +.unlock-dialog .screenshot-ui-show-pointer-button,
 +.unlock-dialog .login-dialog-button.cancel-button,
 +.unlock-dialog .login-dialog-button.switch-user-button,
 +.unlock-dialog .login-dialog-button.login-dialog-session-list-button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(194, 218, 247, 0.25615); }
++  background-color: st-mix(rgba(255, 255, 255, 0.1), #ffffff, 87%); }
 +  .unlock-dialog .button:focus,
 +  .unlock-dialog .icon-button:focus,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:focus,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:focus,
 +  .unlock-dialog .message .message-header .message-expand-button:focus,
 +  .message .message-header .unlock-dialog .message-expand-button:focus,
 +  .unlock-dialog .message .message-header .message-close-button:focus,
 +  .message .message-header .unlock-dialog .message-close-button:focus,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:focus,
 +  .unlock-dialog .login-dialog-button.cancel-button:focus,
 +  .unlock-dialog .login-dialog-button.switch-user-button:focus,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: rgba(199, 221, 248, 0.280945); }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.1), #ffffff, 87%), 5%); }
 +    .unlock-dialog .button:focus:hover,
 +    .unlock-dialog .icon-button:focus:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:focus:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:focus:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:focus:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:focus:hover,
 +    .unlock-dialog .message .message-header .message-close-button:focus:hover,
 +    .message .message-header .unlock-dialog .message-close-button:focus:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:focus:hover {
-     background-color: rgba(255, 255, 255, 0.2431); }
++      background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.13), #ffffff, 87%), 5%); }
 +  .unlock-dialog .button:hover,
 +  .unlock-dialog .icon-button:hover,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:hover,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:hover,
 +  .unlock-dialog .message .message-header .message-expand-button:hover,
 +  .message .message-header .unlock-dialog .message-expand-button:hover,
 +  .unlock-dialog .message .message-header .message-close-button:hover,
 +  .message .message-header .unlock-dialog .message-close-button:hover,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:hover,
 +  .unlock-dialog .login-dialog-button.cancel-button:hover,
 +  .unlock-dialog .login-dialog-button.switch-user-button:hover,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: rgba(255, 255, 255, 0.2692); }
++    background-color: st-mix(rgba(255, 255, 255, 0.13), #ffffff, 87%); }
 +  .unlock-dialog .button:active,
 +  .unlock-dialog .icon-button:active,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:active,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:active,
 +  .unlock-dialog .message .message-header .message-expand-button:active,
 +  .message .message-header .unlock-dialog .message-expand-button:active,
 +  .unlock-dialog .message .message-header .message-close-button:active,
 +  .message .message-header .unlock-dialog .message-close-button:active,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:active,
 +  .unlock-dialog .login-dialog-button.cancel-button:active,
 +  .unlock-dialog .login-dialog-button.switch-user-button:active,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: rgba(204, 224, 248, 0.30574); }
++    background-color: st-mix(rgba(255, 255, 255, 0.16), #ffffff, 87%); }
 +    .unlock-dialog .button:active:hover,
 +    .unlock-dialog .icon-button:active:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:active:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:active:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:active:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:active:hover,
 +    .unlock-dialog .message .message-header .message-close-button:active:hover,
 +    .message .message-header .unlock-dialog .message-close-button:active:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:active:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:active:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:active:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active:hover {
 +      background-color: rgba(255, 255, 255, 0.19); }
 +    .unlock-dialog .button:active:focus,
 +    .unlock-dialog .icon-button:active:focus,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:active:focus,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:active:focus,
 +    .unlock-dialog .message .message-header .message-expand-button:active:focus,
 +    .message .message-header .unlock-dialog .message-expand-button:active:focus,
 +    .unlock-dialog .message .message-header .message-close-button:active:focus,
 +    .message .message-header .unlock-dialog .message-close-button:active:focus,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:active:focus,
 +    .unlock-dialog .login-dialog-button.cancel-button:active:focus,
 +    .unlock-dialog .login-dialog-button.switch-user-button:active:focus,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active:focus {
-     background-color: #5b5b5b; }
++      background-color: st-mix(-st-accent-color, st-mix(rgba(255, 255, 255, 0.16), #ffffff, 87%), 5%); }
 +  .unlock-dialog .button:checked,
 +  .unlock-dialog .icon-button:checked,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:checked,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:checked,
 +  .unlock-dialog .message .message-header .message-expand-button:checked,
 +  .message .message-header .unlock-dialog .message-expand-button:checked,
 +  .unlock-dialog .message .message-header .message-close-button:checked,
 +  .message .message-header .unlock-dialog .message-close-button:checked,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:checked,
 +  .unlock-dialog .login-dialog-button.cancel-button:checked,
 +  .unlock-dialog .login-dialog-button.switch-user-button:checked,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #4d4d4d; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), #ffffff, 87%); }
 +    .unlock-dialog .button:checked:hover,
 +    .unlock-dialog .icon-button:checked:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:checked:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:checked:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:checked:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:checked:hover,
 +    .unlock-dialog .message .message-header .message-close-button:checked:hover,
 +    .message .message-header .unlock-dialog .message-close-button:checked:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked:hover {
-       background-color: #595959; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 4%); }
 +    .unlock-dialog .button:checked:active,
 +    .unlock-dialog .icon-button:checked:active,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:checked:active,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:checked:active,
 +    .unlock-dialog .message .message-header .message-expand-button:checked:active,
 +    .message .message-header .unlock-dialog .message-expand-button:checked:active,
 +    .unlock-dialog .message .message-header .message-close-button:checked:active,
 +    .message .message-header .unlock-dialog .message-close-button:checked:active,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:checked:active,
 +    .unlock-dialog .login-dialog-button.cancel-button:checked:active,
 +    .unlock-dialog .login-dialog-button.switch-user-button:checked:active,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked:active {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #262626;
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 8%), 9%); }
 +  .unlock-dialog .button:insensitive,
 +  .unlock-dialog .icon-button:insensitive,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:insensitive,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:insensitive,
 +  .unlock-dialog .message .message-header .message-expand-button:insensitive,
 +  .message .message-header .unlock-dialog .message-expand-button:insensitive,
 +  .unlock-dialog .message .message-header .message-close-button:insensitive,
 +  .message .message-header .unlock-dialog .message-close-button:insensitive,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:insensitive,
 +  .unlock-dialog .login-dialog-button.cancel-button:insensitive,
 +  .unlock-dialog .login-dialog-button.switch-user-button:insensitive,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(154, 194, 242, 0.145);
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #1a1a1a, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +
 +.unlock-dialog .login-dialog-prompt-entry {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  background-color: rgba(255, 255, 255, 0.1);
 +  color: rgba(255, 255, 255, 0.7); }
 +  .unlock-dialog .login-dialog-prompt-entry:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: rgba(255, 255, 255, 0.1);
 +    color: #ffffff; }
 +  .unlock-dialog .login-dialog-prompt-entry:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: rgba(255, 255, 255, 0.13); }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, rgba(255, 255, 255, 0.1), 5%);
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.7) !important;
-   color: #62a0ea; }
++    background-color: st-mix(rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.1), 5%); }
 +  .unlock-dialog .login-dialog-prompt-entry:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: rgba(247, 247, 247, 0.1);
 +    color: rgba(255, 255, 255, 0.5); }
 +  .unlock-dialog .login-dialog-prompt-entry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
 +/* WIDGETS */
 +.shell-link {
-     color: #8fbbf0; }
++  color: st-lighten(-st-accent-color, 20%); }
 +  .shell-link:hover {
-   width: 24px;
-   height: 24px;
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-off.svg"); }
++    color: st-lighten(st-lighten(-st-accent-color, 20%), 10%); }
 +
 +.lowres-icon {
 +  icon-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); }
 +
 +.icon-dropshadow {
 +  icon-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
 +  icon-shadow: none; }
 +
 +/* Entries */
 +StEntry StIcon.capslock-warning {
 +  icon-size: 1.091em;
 +  warning-color: #f6d32d;
 +  padding: 0 4px; }
 +
 +StEntry StIcon.peek-password {
 +  icon-size: 1.091em;
 +  padding: 0 4px; }
 +
 +StEntry StLabel.hint-text {
 +  margin-left: 2px; }
 +
 +/* Buttons */
 +.button {
 +  min-height: 1.5em; }
 +
 +.icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .screenshot-ui-show-pointer-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button {
 +  border-radius: 999px;
 +  padding: 0.818em;
 +  min-height: 1.091em; }
 +  .icon-button StIcon, .login-dialog-button.cancel-button StIcon, .login-dialog-button.switch-user-button StIcon, .login-dialog-button.login-dialog-session-list-button StIcon, .screenshot-ui-show-pointer-button StIcon, .message .message-header .message-expand-button StIcon,
 +  .message .message-header .message-close-button StIcon, .calendar .calendar-month-header .pager-button StIcon {
 +    icon-size: 1.091em;
 +    -st-icon-style: symbolic; }
 +
 +/* Check Boxes */
 +.check-box StBoxLayout {
 +  spacing: .8em; }
 +
 +.check-box StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-off-focused.svg"); }
++  border-radius: 7px;
++  padding: 2px; }
 +
 +.check-box:focus StBin {
- .check-box:checked StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); }
++  background-color: rgba(0, 0, 0, 0.01);
++  box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.65); }
++
++.check-box StIcon {
++  icon-size: 14px;
++  padding: 1px;
++  color: transparent;
++  border-radius: 6px;
++  border: 2px solid rgba(255, 255, 255, 0.15); }
++
++.check-box:hover StIcon {
++  border-color: rgba(255, 255, 255, 0.2); }
++
++.check-box:active StIcon {
++  border-color: rgba(255, 255, 255, 0.3); }
 +
- .check-box:focus:checked StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); }
++.check-box:checked StIcon {
++  background-color: -st-accent-color;
++  color: -st-accent-fg-color;
++  border-color: transparent; }
 +
-   color: #ffffff;
-   height: 26px;
++.check-box:checked:hover StIcon {
++  background-color: st-lighten(-st-accent-color, 5%);
++  color: st-lighten(-st-accent-fg-color, 5%); }
++
++.check-box:checked:active StIcon {
++  background-color: st-darken(-st-accent-color, 7%);
++  color: st-darken(-st-accent-fg-color, 7%); }
 +
 +/* Switches */
 +.toggle-switch {
-   background-size: contain;
-   background-image: url("resource:///org/gnome/shell/theme/toggle-off.svg"); }
-   .toggle-switch:checked {
-     background-image: url("resource:///org/gnome/shell/theme/toggle-on.svg"); }
 +  width: 46px;
-   -barlevel-background-color: rgba(255, 255, 255, 0.2);
-   -barlevel-border-width: 2px;
-   -barlevel-border-color: transparent;
-   -barlevel-active-background-color: #3584e4;
-   -barlevel-active-border-color: transparent;
++  border-radius: 999px;
++  transition-duration: 100ms;
++  color: #ffffff;
++  background: rgba(255, 255, 255, 0.3); }
++  .toggle-switch:hover {
++    background: rgba(255, 255, 255, 0.4); }
 +  .toggle-switch StIcon {
 +    icon-size: 16px; }
++  .toggle-switch .handle {
++    margin: 3px;
++    width: 20px;
++    height: 20px;
++    border-radius: 999px;
++    background: #d1d1d1;
++    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
++    transition-duration: 100ms; }
++  .toggle-switch:checked {
++    background: -st-accent-color;
++    color: -st-accent-fg-color; }
++    .toggle-switch:checked:hover {
++      background-color: st-lighten(-st-accent-color, 5%);
++      color: st-lighten(-st-accent-fg-color, 5%); }
++    .toggle-switch:checked .handle {
++      background: white; }
 +
 +/* Slider */
 +.slider {
++  color: #e8e8e8;
 +  -barlevel-height: 4px;
-   -barlevel-overdrive-border-color: transparent;
++  -barlevel-background-color: rgba(255, 255, 255, 0.1);
++  -barlevel-active-background-color: -st-accent-color;
 +  -barlevel-overdrive-color: #c01c28;
-   -slider-handle-border-width: 0;
-   -slider-handle-border-color: transparent;
 +  -barlevel-overdrive-separator-width: 1px;
 +  -slider-handle-radius: 0.5455em;
-   .popup-menu-item:focus, .popup-menu-item:hover {
 +  -barlevel-background-color: rgba(255, 255, 255, 0.4); }
++  .slider:hover {
++    color: #ffffff; }
 +
 +/* Scrollbars */
 +StScrollView.vfade {
 +  -st-vfade-offset: 68px; }
 +
 +StScrollView.hfade {
 +  -st-hfade-offset: 68px; }
 +
 +StScrollBar {
 +  padding: 0; }
 +  StScrollView StScrollBar {
 +    min-width: 8px;
 +    min-height: 8px; }
 +  StScrollBar StBin#trough {
 +    border-radius: 0;
 +    background-color: transparent; }
 +  StScrollBar StButton#vhandle, StScrollBar StButton#hhandle {
 +    border-radius: 8px;
 +    background-color: #5e5e5e;
 +    border: 3px solid transparent;
 +    transition: 500ms all ease; }
 +    StScrollBar StButton#vhandle:hover, StScrollBar StButton#hhandle:hover {
 +      background-color: #8c8c8c; }
 +    StScrollBar StButton#vhandle:active, StScrollBar StButton#hhandle:active {
 +      background-color: #757575; }
 +
 +/* Popovers/Menus */
 +.popup-menu-boxpointer, .candidate-popup-boxpointer {
 +  -arrow-rise: 6px; }
 +
 +.popup-menu {
 +  min-width: 15em;
 +  color: #ffffff; }
 +  .popup-menu.panel-menu {
 +    margin-bottom: 1.75em; }
 +
 +.popup-menu-content, .candidate-popup-content {
 +  padding: 6px;
 +  background-color: #1a1a1a;
 +  border-radius: 20px;
 +  border: 1px solid rgba(255, 255, 255, 0.5);
 +  box-shadow: 0 2px 4px 0 transparent; }
 +
 +.popup-menu-item {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  background-color: transparent;
 +  border-color: transparent;
 +  box-shadow: none;
 +  border-radius: 12px; }
 +  .popup-menu-item:insensitive {
 +    background-color: transparent !important; }
-     background-color: #5c5c5c; }
++  .popup-menu-item:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #686868; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #262626, 9%), 4%), #ffffff, 87%); }
 +  .popup-menu-item:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #5b5b5b; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #262626, 9%), 9%), #ffffff, 87%); }
 +    .popup-menu-item:active:hover {
-       background-color: #65696e; }
-   .popup-menu-item:checked {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #262626, 9%), 9%), 4%); }
 +    .popup-menu-item:active:focus {
-     background-color: #656565; }
-     .popup-menu-item:checked:hover {
-       background-color: #595959; }
-     .popup-menu-item:checked:active {
-       background-color: #656565; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #262626, 9%), 9%), #ffffff, 87%), 5%); }
++  .popup-menu-item:selected, .popup-menu-item:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #323232;
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #262626, 9%), 8%), #ffffff, 87%); }
++    .popup-menu-item:selected:hover, .popup-menu-item:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #262626, 9%), 8%), 4%); }
++    .popup-menu-item:selected:active, .popup-menu-item:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #262626, 9%), 8%), 9%); }
 +  .popup-menu-item:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     .popup-sub-menu .popup-menu-item:focus, .popup-sub-menu .popup-menu-item:hover {
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #262626, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .popup-menu-item:checked {
 +    border-radius: 12px 12px 0 0 !important;
 +    border: 1px solid rgba(255, 255, 255, 0.4);
 +    border-bottom-width: 0; }
 +  .popup-menu-item .toggle-switch:ltr {
 +    margin-left: 4px; }
 +  .popup-menu-item .toggle-switch:rtl {
 +    margin-right: 4px; }
 +
 +.popup-ornamented-menu-item:ltr {
 +  padding-left: 6px; }
 +
 +.popup-ornamented-menu-item:rtl {
 +  padding-right: 6px; }
 +
 +.popup-inactive-menu-item {
 +  color: #ffffff; }
 +  .popup-inactive-menu-item:insensitive {
 +    color: #ffffff; }
 +
 +.popup-menu-arrow,
 +.popup-menu-icon {
 +  icon-size: 1.091em; }
 +
 +.popup-sub-menu {
 +  border-radius: 0 0 13px 13px;
 +  margin-bottom: 6px;
 +  border: 1px solid transparent;
 +  background-color: #3b3b3b;
 +  border-color: rgba(255, 255, 255, 0.4); }
 +  .popup-sub-menu .popup-menu-item {
 +    border-radius: 0;
 +    border-top-width: 0;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: transparent;
 +    border-color: transparent;
 +    box-shadow: none; }
 +    .popup-sub-menu .popup-menu-item:insensitive {
 +      background-color: transparent !important; }
-       background-color: #6c6c6c; }
++    .popup-sub-menu .popup-menu-item:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #777777; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 4%), #ffffff, 87%); }
 +    .popup-sub-menu .popup-menu-item:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #6d6d6d; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 9%), #ffffff, 87%); }
 +      .popup-sub-menu .popup-menu-item:active:hover {
-         background-color: #74787c; }
-     .popup-sub-menu .popup-menu-item:checked {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 9%), 4%); }
 +      .popup-sub-menu .popup-menu-item:active:focus {
-       background-color: #757575; }
-       .popup-sub-menu .popup-menu-item:checked:hover {
-         background-color: #6b6b6b; }
-       .popup-sub-menu .popup-menu-item:checked:active {
-         background-color: #777777; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 9%), #ffffff, 87%), 5%); }
++    .popup-sub-menu .popup-menu-item:selected, .popup-sub-menu .popup-menu-item:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       color: rgba(255, 255, 255, 0.5);
-       background-color: #444444;
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 8%), #ffffff, 87%); }
++      .popup-sub-menu .popup-menu-item:selected:hover, .popup-sub-menu .popup-menu-item:checked:hover {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 8%), 4%); }
++      .popup-sub-menu .popup-menu-item:selected:active, .popup-sub-menu .popup-menu-item:checked:active {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #3b3b3b, 9%), 8%), 9%); }
 +    .popup-sub-menu .popup-menu-item:insensitive {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-       color: #ffffff !important; }
++      color: st-transparentize(#ffffff, 0.5);
++      background-color: st-darken(st-mix(#ffffff, #3b3b3b, 9%), 3%);
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      box-shadow: none;
 +      border: none; }
 +    .popup-sub-menu .popup-menu-item:last-child {
 +      border-radius: 0 0 12px 12px;
 +      border-bottom-width: 0; }
 +  .popup-sub-menu .popup-menu-section .popup-menu-item:last-child:hover, .popup-sub-menu .popup-menu-section .popup-menu-item:last-child:focus {
 +    border-radius: 0; }
 +  .popup-sub-menu .popup-menu-section:last-child .popup-menu-item:last-child {
 +    border-radius: 0 0 12px 12px; }
 +
 +.popup-menu-ornament {
 +  icon-size: 1.091em !important;
 +  width: 1.091em; }
 +
 +.popup-separator-menu-item {
 +  border: none !important; }
 +  .popup-separator-menu-item .popup-separator-menu-item-separator {
 +    height: 1px;
 +    background-color: rgba(255, 255, 255, 0.5); }
 +  .popup-sub-menu .popup-separator-menu-item {
 +    background-color: transparent; }
 +    .popup-sub-menu .popup-separator-menu-item:ltr {
 +      margin-right: 2.5em; }
 +    .popup-sub-menu .popup-separator-menu-item:rtl {
 +      margin-left: 2.5em; }
 +    .popup-sub-menu .popup-separator-menu-item .popup-separator-menu-item-separator {
 +      background-color: rgba(255, 255, 255, 0.5); }
 +
 +.background-menu {
 +  -boxpointer-gap: 0px;
 +  -arrow-rise: 0px; }
 +
 +.app-menu {
 +  max-width: 27.25em; }
 +  .app-menu .popup-inactive-menu-item:first-child > StLabel:ltr {
 +    margin-right: 8px; }
 +  .app-menu .popup-inactive-menu-item:first-child > StLabel:rtl {
 +    margin-left: 8px; }
 +
 +/* Date/Time Menu */
 +#calendarArea {
 +  padding: 4px; }
 +
 +.datemenu-popover {
 +  border-radius: 30px; }
 +
 +.datemenu-calendar-column {
 +  spacing: 6px; }
 +  .datemenu-calendar-column:ltr {
 +    margin-left: 6px; }
 +  .datemenu-calendar-column:rtl {
 +    margin-right: 6px; }
 +  .datemenu-calendar-column .datemenu-displays-box {
 +    spacing: 6px; }
 +
 +.datemenu-today-button {
 +  padding: 9px; }
 +  .datemenu-today-button .day-label {
 +    font-weight: bold; }
 +
 +.calendar {
 +  margin-top: 0;
 +  padding: 0; }
 +  .calendar .calendar-month-header .calendar-change-month-back StIcon,
 +  .calendar .calendar-month-header .calendar-change-month-forward StIcon {
 +    icon-size: 1.091em; }
 +  .calendar .calendar-month-header .calendar-month-label {
 +    color: #ffffff !important;
 +    padding: 8px 0;
 +    width: 10em;
 +    border-radius: 999px;
 +    text-align: center; }
 +  .calendar .calendar-month-header .pager-button {
 +    height: 2.6em;
 +    width: 2.6em;
 +    padding: 0; }
 +  .calendar .calendar-day {
 +    border-radius: 999px;
 +    height: 3em;
 +    width: 3em;
 +    margin: 2px;
 +    padding: 0;
 +    font-weight: bold;
 +    text-align: center; }
 +    .calendar .calendar-day.calendar-weekend {
 +      color: #ffffff;
 +      font-style: italic; }
 +    .calendar .calendar-day.calendar-other-month {
 +      color: rgba(255, 255, 255, 0.5);
 +      font-weight: normal;
 +      color: #ffffff;
 +      font-style: italic; }
 +      .calendar .calendar-day.calendar-other-month.calendar-weekend {
 +        color: rgba(255, 255, 255, 0.5);
 +        color: #ffffff; }
 +    .calendar .calendar-day.calendar-today {
-       border-color: rgba(53, 132, 228, 0.6); }
++      color: -st-accent-fg-color !important; }
 +      .calendar .calendar-day.calendar-today.calendar-day-with-events {
 +        background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg") !important; }
 +    .calendar .calendar-day.calendar-day-with-events {
 +      background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
 +      background-size: contain; }
 +  .calendar .calendar-day-heading {
 +    font-weight: bold;
 +    text-align: center;
 +    margin: 4px;
 +    padding: 3px 6px;
 +    border-radius: 8px; }
 +  .calendar .calendar-week-number {
 +    font-weight: bold;
 +    font-feature-settings: "tnum";
 +    text-align: center;
 +    margin: 6px;
 +    padding: 0 6px;
 +    border-radius: 4px;
 +    background-color: rgba(255, 255, 255, 0.2);
 +    color: #ffffff; }
 +
 +.events-button .events-box .events-title {
 +  color: #ffffff;
 +  padding-bottom: 6px; }
 +
 +.events-button .events-box .events-list {
 +  spacing: 6px; }
 +  .events-button .events-box .events-list .event-box {
 +    spacing: 6px;
 +    border-radius: 8px; }
 +    .events-button .events-box .events-list .event-box .event-time {
 +      color: #ffffff; }
 +  .events-button .events-box .events-list .event-placeholder {
 +    color: #ffffff;
 +    font-style: italic; }
 +
 +.world-clocks-button .world-clocks-header {
 +  color: #ffffff; }
 +  .world-clocks-button .world-clocks-header.no-world-clocks {
 +    color: #ffffff; }
 +
 +.world-clocks-button .world-clocks-grid {
 +  spacing-rows: 6px;
 +  spacing-columns: 12px; }
 +  .world-clocks-button .world-clocks-grid .world-clocks-time {
 +    font-weight: bold; }
 +    .world-clocks-button .world-clocks-grid .world-clocks-time:ltr {
 +      text-align: right; }
 +    .world-clocks-button .world-clocks-grid .world-clocks-time:rtl {
 +      text-align: left; }
 +  .world-clocks-button .world-clocks-grid .world-clocks-timezone {
 +    color: #ffffff; }
 +
 +.weather-button .weather-box {
 +  spacing: 6px; }
 +  .weather-button .weather-box .weather-header-box {
 +    spacing: 6px; }
 +    .weather-button .weather-box .weather-header-box .weather-header {
 +      color: #ffffff; }
 +      .weather-button .weather-box .weather-header-box .weather-header.no-location {
 +        color: #ffffff; }
 +      .weather-button .weather-box .weather-header-box .weather-header.location {
 +        font-weight: normal; }
 +  .weather-button .weather-box .weather-grid {
 +    spacing-rows: 6px;
 +    spacing-columns: 12px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-time {
 +      padding-top: 6px;
 +      padding-bottom: 6px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-icon {
 +      icon-size: 2.182em;
 +      margin-bottom: 4px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-temp {
 +      font-weight: bold; }
 +
 +/* Message List */
 +.message-list {
 +  width: 29em;
 +  border: solid rgba(255, 255, 255, 0.5); }
 +  .message-list:ltr {
 +    margin-left: 0;
 +    margin-right: 4px;
 +    padding-right: 6px;
 +    border-right-width: 1px; }
 +  .message-list:rtl {
 +    margin-right: 0;
 +    margin-left: 4px;
 +    padding-left: 6px;
 +    border-left-width: 1px; }
 +  .message-list .message-list-placeholder {
 +    color: rgba(255, 255, 255, 0.25);
 +    color: rgba(255, 255, 255, 0.5); }
 +    .message-list .message-list-placeholder > StIcon {
 +      icon-size: 96px;
 +      margin-bottom: 12px;
 +      -st-icon-style: symbolic; }
 +
 +.message-list-sections {
 +  spacing: 12px; }
 +  .message-list-sections:ltr {
 +    margin-right: 12px; }
 +  .message-list-sections:rtl {
 +    margin-left: 12px; }
 +
 +.message-list-section,
 +.message-list-section-list {
 +  spacing: 12px; }
 +
 +.message-list-controls {
 +  padding: 12px;
 +  padding-bottom: 6px;
 +  spacing: 6px; }
 +  .message-list-controls .dnd-button {
 +    border-width: 2px;
 +    border-color: transparent;
 +    border-radius: 32px;
 +    border-style: solid; }
 +    .message-list-controls .dnd-button:focus {
-   padding: 0;
++      border-color: st-transparentize(-st-accent-color, 0.4); }
 +
 +.message {
-   .message:ltr {
-     padding-right: -2px; }
-   .message:rtl {
-     padding-left: -2px; }
++  padding: 6px;
 +  margin: 0;
 +  border-radius: 16px; }
-     padding: 0 0.409em;
-     margin: 6px;
-     margin-bottom: 0;
 +  .message .message-header {
-     color: #ffffff; }
 +    spacing: 6px;
-       background-color: rgba(255, 255, 255, 0.1);
++    color: #ffffff;
++    padding: 0 6px; }
++    .message .message-header:ltr {
++      padding-right: 4px; }
++    .message .message-header:rtl {
++      padding-left: 4px; }
 +    .message .message-header .message-source-icon {
 +      icon-size: 1.091em;
 +      -st-icon-style: symbolic; }
 +    .message .message-header .message-header-content {
 +      spacing: 6px;
 +      min-height: 1.637em;
 +      padding-bottom: 6px; }
 +      .message .message-header .message-header-content .message-source-title {
 +        font-weight: bold; }
 +      .message .message-header .message-header-content .event-time {
 +        color: #ffffff;
 +        padding-bottom: 0.068em; }
 +        .message .message-header .message-header-content .event-time:ltr {
 +          text-align: right; }
 +        .message .message-header .message-header-content .event-time:rtl {
 +          text-align: left; }
 +    .message .message-header .message-expand-button,
 +    .message .message-header .message-close-button {
++      border-radius: 999px;
 +      color: #ffffff;
-       .message .message-header .message-expand-button:hover,
-       .message .message-header .message-close-button:hover {
-         background-color: rgba(255, 255, 255, 0.19); }
-       .message .message-header .message-expand-button:active, .message .message-header .message-expand-button:active:hover,
-       .message .message-header .message-close-button:active,
-       .message .message-header .message-close-button:active:hover {
-         background-color: rgba(255, 255, 255, 0.24); }
-       .message .message-header .message-expand-button:insensitive,
-       .message .message-header .message-close-button:insensitive {
-         background-color: rgba(255, 255, 255, 0.07); }
 +      padding: 4px; }
-     margin: 6px;
 +    .message .message-header .message-expand-button {
 +      padding: 6px; }
 +      .message .message-header .message-expand-button:ltr {
 +        margin-right: 6px; }
 +      .message .message-header .message-expand-button:rtl {
 +        margin-left: 6px; }
 +  .message .message-box {
 +    padding: 6px;
-   link-color: #62a0ea; }
 +    margin-top: 0;
 +    spacing: 6px; }
 +    .message .message-box .message-icon {
 +      icon-size: 48px; }
 +      .message .message-box .message-icon:ltr {
 +        margin-right: 6px; }
 +      .message .message-box .message-icon:rtl {
 +        margin-left: 6px; }
 +      .message .message-box .message-icon.message-themed-icon {
 +        border-radius: 999px;
 +        background-color: rgba(255, 255, 255, 0.07);
 +        icon-size: 1.091em;
 +        min-width: 48px;
 +        min-height: 48px; }
 +    .message .message-box:first-child {
 +      margin-top: 12px; }
 +    .message .message-box .message-content {
 +      spacing: 4px; }
 +      .message .message-box .message-content .message-title {
 +        font-weight: bold; }
++  .message .message-action-bin {
++    padding: 4px;
++    spacing: 6px; }
++    .message .message-action-bin * {
++      margin: 0 4px; }
++      .message .message-action-bin *:first-child:ltr {
++        margin-left: 0; }
++      .message .message-action-bin *:first-child:rtl {
++        margin-right: 0; }
++      .message .message-action-bin *:last-child:ltr {
++        margin-right: 0; }
++      .message .message-action-bin *:last-child:rtl {
++        margin-left: 0; }
 +
 +.url-highlighter {
-     background-color: #3584e4;
-     color: #ffffff; }
++  link-color: st-lighten(-st-accent-color, 20%); }
 +
 +/* Media Controls */
 +.message-media-control {
 +  padding: 0 18px;
 +  border-radius: 8px;
 +  color: #ffffff;
 +  border: 1px solid transparent;
 +  border-color: rgba(255, 255, 255, 0.4);
 +  margin: 12px 2px; }
 +  .message-media-control:hover {
 +    background-color: #595959;
 +    color: #ffffff; }
 +  .message-media-control:active {
 +    background-color: #5e5e5e;
 +    color: #ffffff; }
 +  .message-media-control:insensitive {
 +    color: white;
 +    border-color: transparent; }
 +  .message-media-control StIcon {
 +    icon-size: 16px; }
 +
 +.media-message .message-icon {
 +  border-radius: 8px !important; }
 +  .media-message .message-icon.message-themed-icon {
 +    icon-size: 32px !important; }
 +
 +.candidate-popup-content {
 +  padding: 6px;
 +  spacing: 6px; }
 +
 +.candidate-index {
 +  padding: 0;
 +  padding-right: 6px;
 +  color: #ffffff; }
 +
 +.candidate-box {
 +  padding: 6px 12px 6px 12px;
 +  border-radius: 8px; }
 +  .candidate-box:selected {
-   border-radius: 16px;
-   box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5); }
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +  .candidate-box:hover {
 +    background-color: #4d4d4d;
 +    color: white; }
 +
 +.candidate-page-button-box {
 +  height: 2em; }
 +  .vertical .candidate-page-button-box {
 +    padding-top: 12px; }
 +  .horizontal .candidate-page-button-box {
 +    padding-left: 12px; }
 +
 +.candidate-page-button {
 +  padding: 6px; }
 +  .candidate-page-button StIcon {
 +    icon-size: 16px; }
 +
 +.candidate-page-button-previous {
 +  border-radius: 8px 0px 0px 8px;
 +  border-right-width: 0;
 +  box-shadow: none; }
 +
 +.candidate-page-button-next {
 +  border-radius: 0px 8px 8px 0px;
 +  box-shadow: none; }
 +
 +/* Notifications & Message Tray */
 +.notification-banner {
 +  min-height: 64px;
 +  width: 34em;
 +  box-shadow: 0 2px 4px 2px transparent;
 +  border-radius: 16px;
 +  margin: 4px;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
 +
 +.notification-buttons-bin {
 +  spacing: 0; }
 +
 +/* Modal Dialogs */
 +.modal-dialog {
 +  background-color: #1a1a1a;
-     margin: 32px 40px;
++  border-radius: 18px;
++  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5);
++  padding: 24px; }
 +  .modal-dialog .modal-dialog-content-box {
-   width: 30em; }
 +    spacing: 32px;
++    margin-top: 8px;
++    margin-bottom: 16px;
 +    max-width: 28em; }
 +
 +/* End Session Dialog */
 +.end-session-dialog {
-     background-color: #3584e4;
-     color: #ffffff; }
++  width: 24em; }
 +  .end-session-dialog .end-session-dialog-battery-warning,
 +  .end-session-dialog .dialog-list-title {
 +    color: #f6d32d; }
 +
 +/* Message Dialog */
 +.message-dialog-content {
 +  spacing: 18px; }
 +  .message-dialog-content .message-dialog-title {
 +    text-align: center; }
 +  .message-dialog-content .message-dialog-description {
 +    text-align: center; }
 +
 +/* Dialog List */
 +.dialog-list {
 +  spacing: 18px; }
 +  .dialog-list .dialog-list-title {
 +    text-align: center; }
 +  .dialog-list .dialog-list-scrollview {
 +    max-height: 200px; }
 +  .dialog-list .dialog-list-box {
 +    spacing: 1em; }
 +    .dialog-list .dialog-list-box .dialog-list-item {
 +      spacing: 1em; }
 +      .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-title {
 +        font-weight: bold; }
 +      .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-description {
 +        color: #f2f2f2; }
 +
 +/* Run Dialog */
 +.run-dialog .modal-dialog-content-box {
 +  margin-top: 24px;
 +  margin-bottom: 12px; }
 +
 +.run-dialog .run-dialog-entry {
 +  width: 20em; }
 +
 +.run-dialog .run-dialog-description {
 +  text-align: center;
 +  color: #cccccc; }
 +
 +/* Password or Authentication Dialog */
 +.prompt-dialog {
 +  width: 28em; }
 +  .prompt-dialog .modal-dialog-content-box {
 +    margin-bottom: 24px; }
 +
 +.prompt-dialog-password-grid {
 +  spacing-rows: 8px;
 +  spacing-columns: 4px; }
 +  .prompt-dialog-password-grid .prompt-dialog-password-entry {
 +    width: auto; }
 +    .prompt-dialog-password-grid .prompt-dialog-password-entry:ltr {
 +      margin-left: 20px; }
 +    .prompt-dialog-password-grid .prompt-dialog-password-entry:rtl {
 +      margin-right: 20px; }
 +
 +.prompt-dialog-password-layout {
 +  spacing: 8px; }
 +
 +.prompt-dialog-password-entry {
 +  width: 20em; }
 +
 +.prompt-dialog-error-label,
 +.prompt-dialog-info-label,
 +.prompt-dialog-null-label {
 +  text-align: center; }
 +
 +.prompt-dialog-error-label {
 +  color: #f6d32d; }
 +
 +/* Polkit Dialog */
 +.polkit-dialog-user-layout {
 +  text-align: center;
 +  spacing: 8px;
 +  margin-bottom: 6px; }
 +  .polkit-dialog-user-layout .polkit-dialog-user-root-label {
 +    color: #f6d32d; }
 +
 +/* Audio selection dialog */
 +.audio-device-selection-dialog .modal-dialog-content-box {
 +  margin-bottom: 28px; }
 +
 +.audio-device-selection-dialog .audio-selection-box {
 +  spacing: 20px; }
 +
 +.audio-selection-device {
 +  border-radius: 16px; }
 +  .audio-selection-device:hover, .audio-selection-device:focus {
 +    background-color: #4d4d4d; }
 +  .audio-selection-device:active {
-   background-color: #3584e4;
-   color: #ffffff;
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +
 +.audio-selection-device-box {
 +  padding: 20px;
 +  spacing: 20px; }
 +
 +.audio-selection-device-icon {
 +  icon-size: 64px; }
 +
 +/* Welcome dialog */
 +.welcome-dialog-image {
 +  background-image: url("resource:///org/gnome/shell/theme/gnome-shell-start.svg");
 +  background-size: contain;
 +  /* Reasonable maximum dimensions */
 +  height: 300px;
 +  width: 300px; }
 +
 +/* Access portal dialog */
 +.access-dialog {
 +  text-align: center; }
 +
 +/* OSD */
 +.osd-window {
 +  text-align: center;
 +  font-weight: bold;
 +  spacing: 12px;
 +  padding: 12px 18px;
 +  margin-bottom: 4em; }
 +  .osd-window > * {
 +    spacing: 8px; }
 +  .osd-window StIcon {
 +    icon-size: 32px; }
 +  .osd-window StLabel:ltr {
 +    margin-right: 6px; }
 +  .osd-window StLabel:rtl {
 +    margin-left: 6px; }
 +  .osd-window .level {
 +    margin-bottom: 4px;
 +    min-width: 160px;
 +    -barlevel-height: 6px;
 +    -barlevel-background-color: rgba(255, 255, 255, 0.1);
 +    -barlevel-active-background-color: #ffffff;
 +    -barlevel-overdrive-color: #c01c28;
 +    -barlevel-overdrive-separator-width: 3px; }
 +    .osd-window .level:first-child {
 +      margin-bottom: 0; }
 +    .osd-window .level:ltr {
 +      margin-right: 6px; }
 +    .osd-window .level:rtl {
 +      margin-left: 6px; }
 +
 +.osd-monitor-label {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-       background-color: rgba(14, 36, 61, 0.2875); }
++  background-color: -st-accent-color;
++  color: -st-accent-fg-color;
 +  border-radius: 16px;
 +  font-size: 3em;
 +  font-weight: bold;
 +  font-feature-settings: "tnum";
 +  margin: 12px;
 +  padding: 12px;
 +  text-align: center;
 +  min-width: 1.5em; }
 +
 +/* Pad OSD */
 +.pad-osd-window {
 +  padding: 32px;
 +  background-color: rgba(0, 0, 0, 0.8); }
 +  .pad-osd-window .pad-osd-title-box {
 +    spacing: 12px; }
 +  .pad-osd-window .pad-osd-title-menu-box {
 +    spacing: 6px; }
 +
 +.combo-box-label {
 +  width: 15em; }
 +
 +/* App Switcher */
 +.switcher-popup {
 +  padding: 0;
 +  spacing: 24px; }
 +
 +.switcher-list {
 +  padding: 12px;
 +  border-radius: 28px;
 +  box-shadow: 0 8px 8px 0 transparent; }
 +  .switcher-list .switcher-list-item-container {
 +    spacing: 12px; }
 +  .switcher-list .item-box {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
 +    background-color: #000000;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +    .switcher-list .item-box:focus {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #31353a; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++      background-color: st-mix(-st-accent-color, rgba(0, 0, 0, 0.25), 5%); }
 +      .switcher-list .item-box:focus:hover {
-       background-color: #313131; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 7%), #ffffff, 87%), 5%); }
 +    .switcher-list .item-box:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #353535; }
++      background-color: st-mix(st-lighten(#000000, 7%), #ffffff, 87%); }
 +    .switcher-list .item-box:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #292929; }
++      background-color: st-mix(st-lighten(#000000, 9%), #ffffff, 87%); }
 +      .switcher-list .item-box:active:hover {
-         background-color: #35393e; }
++        background-color: st-lighten(st-lighten(#000000, 9%), 7%); }
 +      .switcher-list .item-box:active:focus {
-       background-color: #333333; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 9%), #ffffff, 87%), 5%); }
 +    .switcher-list .item-box:highlighted, .switcher-list .item-box:selected, .switcher-list .item-box:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #262626; }
++      background-color: st-mix(st-lighten(#000000, 8%), #ffffff, 87%); }
 +      .switcher-list .item-box:highlighted:hover, .switcher-list .item-box:selected:hover, .switcher-list .item-box:checked:hover {
-         background-color: #2b2b2b; }
++        background-color: st-lighten(st-lighten(#000000, 8%), 7%); }
 +      .switcher-list .item-box:highlighted:active, .switcher-list .item-box:selected:active, .switcher-list .item-box:checked:active {
-       color: rgba(255, 255, 255, 0.5);
++        background-color: st-lighten(st-lighten(#000000, 8%), 9%); }
 +    .switcher-list .item-box:insensitive {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-       background-color: rgba(53, 132, 228, 0.2);
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++      color: st-transparentize(#ffffff, 0.5);
 +      background-color: #000000;
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      box-shadow: none;
 +      border: none; }
 +    .switcher-list .item-box:drop {
-   border: 5px solid #3584e4; }
++      background-color: st-transparentize(-st-accent-color, 0.8);
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +    .switcher-list .item-box:hover {
 +      background: none; }
 +    .switcher-list .item-box:selected {
 +      background-color: rgba(255, 255, 255, 0.2); }
 +    .switcher-list .item-box:selected {
 +      background-color: rgba(255, 255, 255, 0.3); }
 +  .switcher-list .separator {
 +    width: 1px;
 +    background: rgba(255, 255, 255, 0.5); }
 +  .switcher-list .thumbnail-box {
 +    padding: 2px;
 +    spacing: 6px; }
 +  .switcher-list .thumbnail {
 +    width: 256px;
 +    border-radius: 8px; }
 +
 +.switcher-arrow {
 +  border-color: rgba(255, 255, 255, 0.8);
 +  color: rgba(255, 255, 255, 0.8); }
 +  .switcher-arrow:highlighted {
 +    border-color: #ffffff;
 +    color: #ffffff; }
 +
 +.input-source-switcher-symbol {
 +  font-size: 34pt;
 +  width: 96px;
 +  height: 96px; }
 +
 +.cycler-highlight {
-   border-color: #185fb4; }
++  border: 5px solid -st-accent-color; }
 +
 +/* Workspace Switcher */
 +.workspace-switcher {
 +  margin-bottom: 4em;
 +  spacing: 12px;
 +  padding: 12px 18px; }
 +
 +.ws-switcher-indicator {
 +  background-color: rgba(255, 255, 255, 0.5);
 +  padding: 2.6666666667px;
 +  margin: 13.3333333333px;
 +  border-radius: 32px; }
 +  .ws-switcher-indicator:active {
 +    background-color: #ffffff;
 +    padding: 5.3333333333px;
 +    margin: 10.6666666667px; }
 +
 +.screenshot-ui-panel {
 +  border-radius: 32px;
 +  padding: 18px;
 +  padding-bottom: 12px;
 +  margin-bottom: 4em;
 +  spacing: 12px; }
 +
 +.screenshot-ui-close-button {
 +  padding: 6px !important;
 +  margin-top: 12px;
 +  box-shadow: 0 2px 4px 0 transparent; }
 +  .screenshot-ui-close-button.left {
 +    margin-left: 12px; }
 +  .screenshot-ui-close-button.right {
 +    margin-right: 12px; }
 +
 +.screenshot-ui-type-button {
 +  min-width: 48px;
 +  padding: 12px 18px;
 +  border-radius: 14px; }
 +  .screenshot-ui-type-button .icon-label-button-container {
 +    spacing: 0.409em; }
 +    .screenshot-ui-type-button .icon-label-button-container > StIcon {
 +      icon-size: 32px; }
 +
 +.screenshot-ui-capture-button {
 +  width: 32px;
 +  height: 32px;
 +  border-radius: 999px;
 +  border: 4px #ffffff;
 +  padding: 4px; }
 +  .screenshot-ui-capture-button .screenshot-ui-capture-button-circle {
 +    background-color: #ffffff;
 +    transition-duration: 200ms;
 +    border-radius: 999px; }
 +    .screenshot-ui-capture-button .screenshot-ui-capture-button-circle:hover, .screenshot-ui-capture-button .screenshot-ui-capture-button-circle:focus {
 +      background-color: #4d4d4d; }
 +  .screenshot-ui-capture-button:hover .screenshot-ui-capture-button-circle, .screenshot-ui-capture-button:focus .screenshot-ui-capture-button-circle {
 +    background-color: #cccccc; }
 +  .screenshot-ui-capture-button:active .screenshot-ui-capture-button-circle {
 +    background-color: gray; }
 +  .screenshot-ui-capture-button:cast .screenshot-ui-capture-button-circle {
 +    background-color: #c01c28; }
 +  .screenshot-ui-capture-button:cast:hover .screenshot-ui-capture-button-circle, .screenshot-ui-capture-button:cast:focus .screenshot-ui-capture-button-circle {
 +    background-color: #d61f2d; }
 +  .screenshot-ui-capture-button:cast:active .screenshot-ui-capture-button-circle {
 +    background-color: #a11722; }
 +
 +.screenshot-ui-shot-cast-container {
 +  background-color: rgba(255, 255, 255, 0.1);
 +  border-radius: 999px;
 +  padding: 3px;
 +  spacing: 3px;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
 +
 +.screenshot-ui-shot-cast-button {
 +  padding: 6px 12px;
 +  background-color: transparent;
 +  border-radius: 999px;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
 +  .screenshot-ui-shot-cast-button > StIcon {
 +    icon-size: 16px; }
 +  .screenshot-ui-shot-cast-button:hover, .screenshot-ui-shot-cast-button:focus {
 +    background-color: rgba(255, 255, 255, 0.2); }
 +  .screenshot-ui-shot-cast-button:active {
 +    background-color: rgba(255, 255, 255, 0.5); }
 +  .screenshot-ui-shot-cast-button:checked {
 +    background-color: #ffffff;
 +    color: #000000; }
 +  .screenshot-ui-shot-cast-button:insensitive {
 +    color: rgba(255, 255, 255, 0.5); }
 +
 +.screenshot-ui-area-indicator-shade {
 +  background-color: rgba(0, 0, 0, 0.3); }
 +
 +.screenshot-ui-area-selector .screenshot-ui-area-indicator-shade {
 +  background-color: rgba(0, 0, 0, 0.5); }
 +
 +.screenshot-ui-area-selector .screenshot-ui-area-indicator-selection {
 +  border: 2px white; }
 +
 +.screenshot-ui-area-selector-handle {
 +  border-radius: 999px;
 +  background-color: white;
 +  box-shadow: 0 1px 3px 2px transparent;
 +  width: 24px;
 +  height: 24px; }
 +
 +.screenshot-ui-window-selector {
 +  background-color: #000000; }
 +  .screenshot-ui-window-selector .screenshot-ui-window-selector-window-container {
 +    margin: 100px; }
 +  .screenshot-ui-window-selector:primary-monitor .screenshot-ui-window-selector-window-container {
 +    margin-bottom: 200px; }
 +
 +.screenshot-ui-window-selector-window-border {
 +  transition-duration: 200ms;
 +  border-radius: 16px;
 +  border: 6px transparent; }
 +
 +.screenshot-ui-window-selector-check {
 +  transition-duration: 200ms;
 +  color: transparent;
 +  border-radius: 999px;
 +  border-width: 12px;
 +  icon-size: 24px; }
 +
 +.screenshot-ui-window-selector-window:hover .screenshot-ui-window-selector-window-border {
-   border-color: #3584e4;
-   background-color: rgba(53, 132, 228, 0.2); }
++  border-color: st-darken(-st-accent-color, 15%); }
 +
 +.screenshot-ui-window-selector-window:checked .screenshot-ui-window-selector-window-border {
-   color: #ffffff;
-   background-color: #3584e4; }
++  border-color: -st-accent-color;
++  background-color: st-transparentize(-st-accent-color, 0.8); }
 +
 +.screenshot-ui-window-selector-window:checked .screenshot-ui-window-selector-check {
-     border-color: #bcd6f6; }
++  color: -st-accent-fg-color;
++  background-color: -st-accent-color; }
 +
 +.screenshot-ui-screen-selector {
 +  transition-duration: 200ms;
 +  background-color: rgba(0, 0, 0, 0.5); }
 +  .screenshot-ui-screen-selector:hover {
 +    background-color: rgba(0, 0, 0, 0.3); }
 +  .screenshot-ui-screen-selector:active {
 +    background-color: rgba(0, 0, 0, 0.7); }
 +  .screenshot-ui-screen-selector:checked {
 +    background-color: transparent;
 +    border: 2px white; }
 +
 +.screenshot-ui-tooltip {
 +  text-align: center;
 +  -y-offset: 24px; }
 +
 +/* Top Bar */
 +#panel {
 +  background-color: #000000;
 +  font-weight: bold;
 +  height: 2.2em;
 +  transition-duration: 250ms; }
 +  #panel .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 100px transparent;
 +    -natural-hpadding: 12px;
 +    -minimum-hpadding: 6px; }
 +    #panel .panel-button:focus, #panel .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +    #panel .panel-button:active, #panel .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +      #panel .panel-button:active:hover, #panel .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +    #panel .panel-button .system-status-icon {
 +      icon-size: 1.091em;
 +      padding: 0 6px;
 +      margin: 0 4px; }
 +    #panel .panel-button .app-menu-icon {
 +      -st-icon-style: symbolic; }
 +    #panel .panel-button .panel-status-menu-box,
 +    #panel .panel-button .panel-status-indicators-box {
 +      spacing: 4px; }
 +      #panel .panel-button .panel-status-menu-box > .system-status-icon,
 +      #panel .panel-button .panel-status-indicators-box > .system-status-icon {
 +        padding: 0; }
 +    #panel .panel-button#panelActivities StBoxLayout {
 +      padding: 0 0.2045em;
 +      spacing: 5px; }
 +    #panel .panel-button#panelActivities .workspace-dot {
 +      border-radius: 999px;
 +      min-width: 0.5455em;
 +      min-height: 0.5455em;
 +      background-color: #ffffff; }
 +    #panel .panel-button.screen-recording-indicator StBoxLayout, #panel .panel-button.screen-sharing-indicator StBoxLayout {
 +      spacing: 0.409em; }
 +    #panel .panel-button.screen-recording-indicator StIcon, #panel .panel-button.screen-sharing-indicator StIcon {
 +      icon-size: 1.091em; }
 +    #panel .panel-button.screen-recording-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #c01c28; }
 +      #panel .panel-button.screen-recording-indicator:focus, #panel .panel-button.screen-recording-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #d61f2d; }
 +      #panel .panel-button.screen-recording-indicator:active, #panel .panel-button.screen-recording-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #e02a37; }
 +        #panel .panel-button.screen-recording-indicator:active:hover, #panel .panel-button.screen-recording-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #e13340; }
 +    #panel .panel-button.screen-sharing-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #ff7800; }
 +      #panel .panel-button.screen-sharing-indicator:focus, #panel .panel-button.screen-sharing-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #ff861a; }
 +      #panel .panel-button.screen-sharing-indicator:active, #panel .panel-button.screen-sharing-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #ff902e; }
 +        #panel .panel-button.screen-sharing-indicator:active:hover, #panel .panel-button.screen-sharing-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #ff9638; }
 +    #panel .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #ffffff;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel .panel-button.clock-display:focus, #panel .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel .panel-button.clock-display:active, #panel .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel .panel-button.clock-display:active:hover, #panel .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel .panel-button.clock-display:focus .clock, #panel .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel .panel-button.clock-display:active .clock, #panel .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel .panel-button.clock-display:active .clock:hover, #panel .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel .panel-button.clock-display .messages-indicator {
 +        icon-size: 1.091em; }
 +  #panel:overview, #panel.unlock-screen, #panel.login-screen {
 +    background-color: transparent; }
 +    #panel:overview .panel-button.screen-recording-indicator, #panel.unlock-screen .panel-button.screen-recording-indicator, #panel.login-screen .panel-button.screen-recording-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #c01c28; }
 +      #panel:overview .panel-button.screen-recording-indicator:focus, #panel:overview .panel-button.screen-recording-indicator:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:focus, #panel.unlock-screen .panel-button.screen-recording-indicator:hover, #panel.login-screen .panel-button.screen-recording-indicator:focus, #panel.login-screen .panel-button.screen-recording-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #d61f2d; }
 +      #panel:overview .panel-button.screen-recording-indicator:active, #panel:overview .panel-button.screen-recording-indicator:checked, #panel.unlock-screen .panel-button.screen-recording-indicator:active, #panel.unlock-screen .panel-button.screen-recording-indicator:checked, #panel.login-screen .panel-button.screen-recording-indicator:active, #panel.login-screen .panel-button.screen-recording-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #e02a37; }
 +        #panel:overview .panel-button.screen-recording-indicator:active:hover, #panel:overview .panel-button.screen-recording-indicator:checked:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:active:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:checked:hover, #panel.login-screen .panel-button.screen-recording-indicator:active:hover, #panel.login-screen .panel-button.screen-recording-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #e13340; }
 +    #panel:overview .panel-button.screen-sharing-indicator, #panel.unlock-screen .panel-button.screen-sharing-indicator, #panel.login-screen .panel-button.screen-sharing-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #ff7800; }
 +      #panel:overview .panel-button.screen-sharing-indicator:focus, #panel:overview .panel-button.screen-sharing-indicator:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:focus, #panel.unlock-screen .panel-button.screen-sharing-indicator:hover, #panel.login-screen .panel-button.screen-sharing-indicator:focus, #panel.login-screen .panel-button.screen-sharing-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #ff861a; }
 +      #panel:overview .panel-button.screen-sharing-indicator:active, #panel:overview .panel-button.screen-sharing-indicator:checked, #panel.unlock-screen .panel-button.screen-sharing-indicator:active, #panel.unlock-screen .panel-button.screen-sharing-indicator:checked, #panel.login-screen .panel-button.screen-sharing-indicator:active, #panel.login-screen .panel-button.screen-sharing-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #ff902e; }
 +        #panel:overview .panel-button.screen-sharing-indicator:active:hover, #panel:overview .panel-button.screen-sharing-indicator:checked:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:active:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:checked:hover, #panel.login-screen .panel-button.screen-sharing-indicator:active:hover, #panel.login-screen .panel-button.screen-sharing-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #ff9638; }
 +  #panel.unlock-screen .panel-button, #panel.login-screen .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 100px transparent; }
 +    #panel.unlock-screen .panel-button:focus, #panel.unlock-screen .panel-button:hover, #panel.login-screen .panel-button:focus, #panel.login-screen .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +    #panel.unlock-screen .panel-button:active, #panel.unlock-screen .panel-button:checked, #panel.login-screen .panel-button:active, #panel.login-screen .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +      #panel.unlock-screen .panel-button:active:hover, #panel.unlock-screen .panel-button:checked:hover, #panel.login-screen .panel-button:active:hover, #panel.login-screen .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +    #panel.unlock-screen .panel-button.clock-display, #panel.login-screen .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #ffffff;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel.unlock-screen .panel-button.clock-display:focus, #panel.unlock-screen .panel-button.clock-display:hover, #panel.login-screen .panel-button.clock-display:focus, #panel.login-screen .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel.unlock-screen .panel-button.clock-display:active, #panel.unlock-screen .panel-button.clock-display:checked, #panel.login-screen .panel-button.clock-display:active, #panel.login-screen .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel.unlock-screen .panel-button.clock-display:active:hover, #panel.unlock-screen .panel-button.clock-display:checked:hover, #panel.login-screen .panel-button.clock-display:active:hover, #panel.login-screen .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel.unlock-screen .panel-button.clock-display .clock, #panel.login-screen .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel.unlock-screen .panel-button.clock-display:focus .clock, #panel.unlock-screen .panel-button.clock-display:hover .clock, #panel.login-screen .panel-button.clock-display:focus .clock, #panel.login-screen .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel.unlock-screen .panel-button.clock-display:active .clock, #panel.unlock-screen .panel-button.clock-display:checked .clock, #panel.login-screen .panel-button.clock-display:active .clock, #panel.login-screen .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel.unlock-screen .panel-button.clock-display:active .clock:hover, #panel.unlock-screen .panel-button.clock-display:checked .clock:hover, #panel.login-screen .panel-button.clock-display:active .clock:hover, #panel.login-screen .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +  #panel:overview .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 100px transparent; }
 +    #panel:overview .panel-button:focus, #panel:overview .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +    #panel:overview .panel-button:active, #panel:overview .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +      #panel:overview .panel-button:active:hover, #panel:overview .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +    #panel:overview .panel-button#panelActivities .workspace-dot {
 +      background-color: #ffffff; }
 +    #panel:overview .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #ffffff;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel:overview .panel-button.clock-display:focus, #panel:overview .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel:overview .panel-button.clock-display:active, #panel:overview .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel:overview .panel-button.clock-display:active:hover, #panel:overview .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel:overview .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel:overview .panel-button.clock-display:focus .clock, #panel:overview .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel:overview .panel-button.clock-display:active .clock, #panel:overview .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel:overview .panel-button.clock-display:active .clock:hover, #panel:overview .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +  #panel .panel-status-indicators-box,
 +  #panel .panel-status-menu-box {
 +    spacing: 2px; }
 +  #panel .power-status.panel-status-indicators-box {
 +    spacing: 0; }
 +  #panel .privacy-indicator {
 +    color: #ff7800; }
 +
 +#appMenu {
 +  spacing: 0.409em; }
 +  #appMenu .label-shadow {
 +    color: transparent; }
 +
 +#appMenu .panel-status-menu-box {
 +  padding: 0 0.409em;
 +  spacing: 0.409em; }
 +
 +.clock-display-box {
 +  spacing: 2px; }
 +  .clock-display-box .clock {
 +    padding-left: 0.818em;
 +    padding-right: 0.818em; }
 +
 +/* Activities Ripple */
 +.ripple-box {
 +  background-color: rgba(255, 255, 255, 0.2);
 +  box-shadow: 0 0 2px 2px rgba(255, 255, 255, 0.2);
 +  width: 52px;
 +  height: 52px;
 +  border-radius: 0 0 52px 0; }
 +  .ripple-box:rtl {
 +    border-radius: 0 0 0 52px; }
 +
 +.quick-settings {
 +  padding: 18px;
 +  border-radius: 36px; }
 +  .quick-settings .icon-button, .quick-settings .login-dialog-button.cancel-button, .quick-settings .login-dialog-button.switch-user-button, .quick-settings .login-dialog-button.login-dialog-session-list-button, .quick-settings .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .quick-settings .pager-button, .quick-settings .message .message-header .message-expand-button, .message .message-header .quick-settings .message-expand-button,
 +  .quick-settings .message .message-header .message-close-button,
 +  .message .message-header .quick-settings .message-close-button, .quick-settings .screenshot-ui-show-pointer-button, .quick-settings .button {
 +    padding: 10.5px; }
 +
 +.quick-settings-grid {
 +  spacing-rows: 12px;
 +  spacing-columns: 12px; }
 +
 +.quick-toggle, .quick-menu-toggle {
 +  border-radius: 999px;
 +  min-width: 12em;
 +  max-width: 12em;
 +  min-height: 3.273em;
 +  border: none; }
 +
 +.quick-toggle {
 +  background-color: none;
 +  /* Move padding into the box; this is to allow menu arrows
 +     to extend to the border */ }
 +  .quick-toggle > StBoxLayout {
 +    spacing: 9px; }
 +  .quick-toggle.button {
 +    padding: 0; }
 +  .quick-toggle > StBoxLayout {
 +    padding: 0 12px; }
 +  .quick-toggle:ltr > StBoxLayout {
 +    padding-left: 15px; }
 +  .quick-toggle:rtl > StBoxLayout {
 +    padding-right: 15px; }
 +  .quick-toggle .quick-toggle-title {
 +    font-weight: bold; }
 +  .quick-toggle StBoxLayout > .quick-toggle-subtitle {
 +    font-weight: normal; }
 +  .quick-toggle .quick-toggle-icon {
 +    icon-size: 1.091em; }
 +
 +.quick-menu-toggle .quick-toggle {
 +  min-width: auto;
 +  max-width: auto; }
 +  .quick-menu-toggle .quick-toggle:ltr {
 +    border-radius: 999px 0 0 999px; }
 +  .quick-menu-toggle .quick-toggle:ltr > StBoxLayout {
 +    padding-right: 0.6135em; }
 +  .quick-menu-toggle .quick-toggle:rtl {
 +    border-radius: 0 999px 999px 0; }
 +  .quick-menu-toggle .quick-toggle:rtr > StBoxLayout {
 +    padding-left: 0.6135em; }
 +  .quick-menu-toggle .quick-toggle:ltr:last-child {
 +    border-radius: 999px; }
 +  .quick-menu-toggle .quick-toggle:rtl:last-child {
 +    border-radius: 999px; }
 +
 +.quick-menu-toggle .quick-toggle-arrow {
 +  padding: 0.409em 0.71575em;
 +  border-width: 0;
 +  border-color: rgba(255, 255, 255, 0.25); }
 +  .quick-menu-toggle .quick-toggle-arrow:checked {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #484c51; }
++    border-color: st-lighten(-st-accent-color, 30%); }
 +  .quick-menu-toggle .quick-toggle-arrow:ltr {
 +    border-radius: 0 999px 999px 0;
 +    border-left-width: 1px; }
 +  .quick-menu-toggle .quick-toggle-arrow:rtl {
 +    border-radius: 999px 0 0 999px;
 +    border-right-width: 1px; }
 +
 +.quick-slider > StBoxLayout {
 +  spacing: 6px; }
 +
 +.quick-slider .icon-button, .quick-slider .login-dialog-button.cancel-button, .quick-slider .login-dialog-button.switch-user-button, .quick-slider .login-dialog-button.login-dialog-session-list-button, .quick-slider .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .quick-slider .pager-button, .quick-slider .message .message-header .message-expand-button, .message .message-header .quick-slider .message-expand-button,
 +.quick-slider .message .message-header .message-close-button,
 +.message .message-header .quick-slider .message-close-button, .quick-slider .screenshot-ui-show-pointer-button {
 +  padding: 6px; }
 +
 +.quick-slider .slider-bin {
 +  padding: 6px;
 +  border-radius: 999px; }
 +  .quick-slider .slider-bin:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #515559; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%), 5%); }
 +    .quick-slider .slider-bin:focus:hover {
-     background-color: #494949; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 4%), #ffffff, 87%), 5%); }
 +
 +.quick-toggle-menu {
 +  border-radius: 24px;
 +  margin: 12px 18px 0; }
 +  .quick-toggle-menu:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-         background-color: #3584e4;
-         color: #ffffff; }
++    background-color: st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%); }
 +  .quick-toggle-menu .popup-menu-item > StIcon {
 +    -st-icon-style: symbolic;
 +    icon-size: 1.091em; }
 +  .quick-toggle-menu .header {
 +    spacing-rows: 3px;
 +    spacing-columns: 12px;
 +    padding-bottom: 12px; }
 +    .quick-toggle-menu .header .icon {
 +      icon-size: 1.6365em;
 +      border-radius: 999px;
 +      padding: 9px;
 +      background-color: rgba(255, 255, 255, 0.2);
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
 +      .quick-toggle-menu .header .icon.active {
-     background-color: #494949;
++        background-color: -st-accent-color;
++        color: -st-accent-fg-color; }
 +      .quick-toggle-menu .header .icon.active {
 +        box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +        box-shadow: none;
 +        border: none; }
 +
 +.quick-settings-system-item > StBoxLayout {
 +  spacing: 12px; }
 +
 +.quick-settings-system-item .power-item {
 +  min-height: 0;
 +  min-width: 0; }
 +  .quick-settings-system-item .power-item:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
- .controls-manager, .secondary-monitor-workspaces {
++    background-color: st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%);
 +    background-color: transparent; }
 +
 +.nm-network-item .wireless-secure-icon {
 +  icon-size: 0.5455em; }
 +
 +.bt-device-item .popup-menu-icon {
 +  -st-icon-style: symbolic; }
 +
 +.bt-menu-placeholder.popup-menu-item {
 +  text-align: center;
 +  padding: 2em 4em; }
 +
 +.device-subtitle {
 +  color: rgba(255, 255, 255, 0.5); }
 +
 +.keyboard-brightness-level {
 +  spacing: 6px; }
 +
 +.background-apps-quick-toggle {
 +  min-height: 2.728em;
 +  background-color: transparent; }
 +  .background-apps-quick-toggle StIcon {
 +    icon-size: 1.091em !important; }
 +
 +.background-app-item .popup-menu-icon {
 +  icon-size: 32px !important;
 +  -st-icon-style: regular !important; }
 +
 +.background-app-item .icon-button, .background-app-item .login-dialog-button.cancel-button, .background-app-item .login-dialog-button.switch-user-button, .background-app-item .login-dialog-button.login-dialog-session-list-button, .background-app-item .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .background-app-item .pager-button, .background-app-item .message .message-header .message-expand-button, .message .message-header .background-app-item .message-expand-button,
 +.background-app-item .message .message-header .message-close-button,
 +.message .message-header .background-app-item .message-close-button, .background-app-item .screenshot-ui-show-pointer-button {
 +  padding: 6px;
 +  background-color: rgba(255, 255, 255, 0.13); }
 +  .background-app-item .icon-button:hover, .background-app-item .login-dialog-button.cancel-button:hover, .background-app-item .login-dialog-button.switch-user-button:hover, .background-app-item .login-dialog-button.login-dialog-session-list-button:hover, .background-app-item .calendar .calendar-month-header .pager-button:hover, .calendar .calendar-month-header .background-app-item .pager-button:hover, .background-app-item .message .message-header .message-expand-button:hover, .message .message-header .background-app-item .message-expand-button:hover,
 +  .background-app-item .message .message-header .message-close-button:hover,
 +  .message .message-header .background-app-item .message-close-button:hover, .background-app-item .screenshot-ui-show-pointer-button:hover {
 +    background-color: rgba(255, 255, 255, 0.22); }
 +  .background-app-item .icon-button:active, .background-app-item .login-dialog-button.cancel-button:active, .background-app-item .login-dialog-button.switch-user-button:active, .background-app-item .login-dialog-button.login-dialog-session-list-button:active, .background-app-item .calendar .calendar-month-header .pager-button:active, .calendar .calendar-month-header .background-app-item .pager-button:active, .background-app-item .message .message-header .message-expand-button:active, .message .message-header .background-app-item .message-expand-button:active,
 +  .background-app-item .message .message-header .message-close-button:active,
 +  .message .message-header .background-app-item .message-close-button:active, .background-app-item .screenshot-ui-show-pointer-button:active {
 +    background-color: rgba(255, 255, 255, 0.31); }
 +
 +.background-app-item .spinner {
 +  padding: 6px; }
 +
 +.background-app-item.popup-inactive-menu-item {
 +  color: #ffffff; }
 +
 +/* OVERVIEW */
- .overview-controls {
-   padding-bottom: 32px; }
- 
++.secondary-monitor-workspaces {
 +  spacing: 12px; }
 +
 +#overviewGroup {
 +  background-color: #000000; }
 +
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(41, 63, 88, 0.2875); }
 +/* Window Picker */
 +.window-picker {
 +  spacing: 6px; }
 +
 +.window-icon {
 +  background-color: #000000;
 +  padding: 12px;
 +  border-radius: 16px;
 +  border: 2px solid rgba(255, 255, 255, 0.4);
 +  margin: 18px; }
 +
 +.window-close, .screenshot-ui-close-button {
 +  background-color: rgba(31, 31, 31, 0.98);
 +  color: #ffffff;
 +  border-radius: 999px;
 +  box-shadow: 0 2px 4px 0 transparent;
 +  padding: 3px;
 +  height: 32px;
 +  width: 32px;
 +  transition-duration: 100ms;
 +  border: 2px solid transparent;
 +  border-color: rgba(255, 255, 255, 0.4); }
 +  .window-close StIcon, .screenshot-ui-close-button StIcon {
 +    icon-size: 24px; }
 +  .window-close:hover, .screenshot-ui-close-button:hover {
 +    background-color: rgba(48, 48, 48, 0.98); }
 +  .window-close:active, .screenshot-ui-close-button:active {
 +    background-color: rgba(64, 64, 64, 0.98); }
 +
 +.workspace-background {
 +  border-radius: 30px;
 +  background-color: rgba(3, 2, 1, 0);
 +  box-shadow: 0 4px 16px 4px transparent; }
 +
 +.search-entry {
 +  border-radius: 999px;
 +  margin-top: 12px;
 +  margin-bottom: 6px;
 +  width: 24em; }
 +  .search-entry .search-entry-icon {
 +    icon-size: 1.091em;
 +    margin-top: 2px;
 +    padding: 0 4px; }
 +
 +/* Search */
 +#searchResults {
 +  margin: 0 4px; }
 +
 +#searchResultsContent {
 +  max-width: 1044px; }
 +
 +.search-section {
 +  spacing: 18px; }
 +  .search-section .search-section-separator {
 +    height: 8px;
 +    background-color: transparent; }
 +
 +.search-section-content {
 +  background-color: #252525;
 +  color: #ffffff;
 +  border-radius: 24px;
 +  padding: 12px;
 +  margin: 0 12px;
 +  border: 2px solid transparent;
 +  border-color: rgba(255, 255, 255, 0.4); }
 +
 +.list-search-result, .search-provider-icon {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
 +  background-color: #252525;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none;
 +  border-radius: 13.2px; }
 +  .list-search-result:focus, .search-provider-icon:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #505458; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, rgba(37, 37, 37, 0.25), 5%); }
 +    .list-search-result:focus:hover, .search-provider-icon:focus:hover {
-     background-color: #515151; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 7%), #ffffff, 87%), 5%); }
 +  .list-search-result:hover, .search-provider-icon:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #555555; }
++    background-color: st-mix(st-lighten(#252525, 7%), #ffffff, 87%); }
 +  .list-search-result:active, .search-provider-icon:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #4e4e4e; }
++    background-color: st-mix(st-lighten(#252525, 9%), #ffffff, 87%); }
 +    .list-search-result:active:hover, .search-provider-icon:active:hover {
-       background-color: #53575c; }
++      background-color: st-lighten(st-lighten(#252525, 9%), 7%); }
 +    .list-search-result:active:focus, .search-provider-icon:active:focus {
-     background-color: #535353; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 9%), #ffffff, 87%), 5%); }
 +  .list-search-result:highlighted, .search-provider-icon:highlighted, .list-search-result:selected, .search-provider-icon:selected, .list-search-result:checked, .search-provider-icon:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #4b4b4b; }
++    background-color: st-mix(st-lighten(#252525, 8%), #ffffff, 87%); }
 +    .list-search-result:highlighted:hover, .search-provider-icon:highlighted:hover, .list-search-result:selected:hover, .search-provider-icon:selected:hover, .list-search-result:checked:hover, .search-provider-icon:checked:hover {
-       background-color: #505050; }
++      background-color: st-lighten(st-lighten(#252525, 8%), 7%); }
 +    .list-search-result:highlighted:active, .search-provider-icon:highlighted:active, .list-search-result:selected:active, .search-provider-icon:selected:active, .list-search-result:checked:active, .search-provider-icon:checked:active {
-     color: rgba(255, 255, 255, 0.5);
++      background-color: st-lighten(st-lighten(#252525, 8%), 9%); }
 +  .list-search-result:insensitive, .search-provider-icon:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: rgba(53, 132, 228, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++    color: st-transparentize(#ffffff, 0.5);
 +    background-color: #252525;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .list-search-result:drop, .search-provider-icon:drop {
-   margin-top: 12px; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.search-statustext {
 +  color: rgba(255, 255, 255, 0.8); }
 +
 +.grid-search-results {
 +  spacing: 30px; }
 +
 +.search-provider-icon:ltr {
 +  margin-right: 4px; }
 +
 +.search-provider-icon:rtl {
 +  margin-left: 4px; }
 +
 +.search-provider-icon .list-search-provider-content {
 +  spacing: 12px; }
 +  .search-provider-icon .list-search-provider-content .list-search-provider-details {
 +    width: 120px;
 +    color: #ffffff; }
 +
 +.list-search-results {
 +  spacing: 6px; }
 +
 +.list-search-result .list-search-result-content {
 +  spacing: 6px; }
 +
 +.list-search-result .list-search-result-title {
 +  spacing: 12px;
 +  font-weight: bold; }
 +
 +.list-search-result .list-search-result-description {
 +  color: #868686;
 +  color: #ffffff; }
 +
 +/* Dash */
 +#dash {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-       background-color: rgba(41, 63, 88, 0.2875); }
++  padding-left: 6px;
++  padding-right: 6px; }
 +  #dash .dash-background {
 +    background-color: #252525;
 +    border-radius: 28px;
 +    padding-top: 12px;
 +    padding-bottom: 12px;
 +    padding-left: 10px;
 +    padding-right: 10px;
 +    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.4); }
 +  #dash .dash-item-container .placeholder {
 +    background-image: none;
 +    background-size: contain;
 +    height: 32px; }
 +  #dash .dash-item-container .empty-dash-drop-target {
 +    width: 32px;
 +    height: 32px; }
 +  #dash .dash-item-container .show-apps,
 +  #dash .dash-item-container .overview-tile,
 +  #dash .dash-item-container .grid-search-result {
 +    margin: 0 2px;
 +    padding-bottom: 12px; }
 +    #dash .dash-item-container .show-apps .overview-icon,
 +    #dash .dash-item-container .overview-tile .overview-icon,
 +    #dash .dash-item-container .grid-search-result .overview-icon {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
 +      background-color: #252525;
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      box-shadow: none;
 +      border: none; }
 +    #dash .dash-item-container .show-apps:focus .overview-icon,
 +    #dash .dash-item-container .overview-tile:focus .overview-icon,
 +    #dash .dash-item-container .grid-search-result:focus .overview-icon {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #505458; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++      background-color: st-mix(-st-accent-color, rgba(37, 37, 37, 0.25), 5%); }
 +      #dash .dash-item-container .show-apps:focus .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:focus .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:focus .overview-icon:hover {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 7%), #ffffff, 87%), 5%); }
 +    #dash .dash-item-container .show-apps:hover .overview-icon,
 +    #dash .dash-item-container .overview-tile:hover .overview-icon,
 +    #dash .dash-item-container .grid-search-result:hover .overview-icon {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #555555; }
++      background-color: st-mix(st-lighten(#252525, 7%), #ffffff, 87%); }
 +    #dash .dash-item-container .show-apps:active .overview-icon,
 +    #dash .dash-item-container .overview-tile:active .overview-icon,
 +    #dash .dash-item-container .grid-search-result:active .overview-icon {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #4e4e4e; }
++      background-color: st-mix(st-lighten(#252525, 9%), #ffffff, 87%); }
 +      #dash .dash-item-container .show-apps:active .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:active .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:active .overview-icon:hover {
-         background-color: #53575c; }
++        background-color: st-lighten(st-lighten(#252525, 9%), 7%); }
 +      #dash .dash-item-container .show-apps:active .overview-icon:focus,
 +      #dash .dash-item-container .overview-tile:active .overview-icon:focus,
 +      #dash .dash-item-container .grid-search-result:active .overview-icon:focus {
-       background-color: #535353; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 9%), #ffffff, 87%), 5%); }
 +    #dash .dash-item-container .show-apps:checked .overview-icon,
 +    #dash .dash-item-container .overview-tile:checked .overview-icon,
 +    #dash .dash-item-container .grid-search-result:checked .overview-icon {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #4b4b4b; }
++      background-color: st-mix(st-lighten(#252525, 8%), #ffffff, 87%); }
 +      #dash .dash-item-container .show-apps:checked .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:checked .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:checked .overview-icon:hover {
-         background-color: #505050; }
++        background-color: st-lighten(st-lighten(#252525, 8%), 7%); }
 +      #dash .dash-item-container .show-apps:checked .overview-icon:active,
 +      #dash .dash-item-container .overview-tile:checked .overview-icon:active,
 +      #dash .dash-item-container .grid-search-result:checked .overview-icon:active {
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(14, 36, 61, 0.2875); }
++        background-color: st-lighten(st-lighten(#252525, 8%), 9%); }
 +  #dash .dash-item-container .app-grid-running-dot {
 +    offset-y: -13px; }
 +  #dash .dash-separator {
 +    width: 1px;
 +    margin-left: 4px;
 +    margin-right: 4px;
 +    background-color: rgba(255, 255, 255, 0.1);
 +    width: 2px;
 +    background-color: rgba(255, 255, 255, 0.4); }
 +  #dash .dash-separator,
 +  #dash .dash-background {
 +    margin-bottom: 12px; }
 +
 +.dash-label {
 +  -y-offset: 8px; }
 +
 +/* App Grid */
 +.icon-grid {
 +  row-spacing: 12px;
 +  column-spacing: 12px;
 +  max-row-spacing: 36px;
 +  max-column-spacing: 36px;
 +  page-padding-top: 24px;
 +  page-padding-bottom: 24px;
 +  page-padding-left: 18px;
 +  page-padding-right: 18px; }
 +
 +/* App Icons */
 +.overview-tile, .grid-search-result {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
 +  background-color: #000000;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none;
 +  border-radius: 24px;
 +  padding: 12px; }
 +  .overview-tile:focus, .grid-search-result:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #31353a; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, rgba(0, 0, 0, 0.25), 5%); }
 +    .overview-tile:focus:hover, .grid-search-result:focus:hover {
-     background-color: #313131; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 7%), #ffffff, 87%), 5%); }
 +  .overview-tile:hover, .grid-search-result:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #353535; }
++    background-color: st-mix(st-lighten(#000000, 7%), #ffffff, 87%); }
 +  .overview-tile:active, .grid-search-result:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #292929; }
++    background-color: st-mix(st-lighten(#000000, 9%), #ffffff, 87%); }
 +    .overview-tile:active:hover, .grid-search-result:active:hover {
-       background-color: #35393e; }
++      background-color: st-lighten(st-lighten(#000000, 9%), 7%); }
 +    .overview-tile:active:focus, .grid-search-result:active:focus {
-     background-color: #333333; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 9%), #ffffff, 87%), 5%); }
 +  .overview-tile:highlighted, .grid-search-result:highlighted, .overview-tile:selected, .grid-search-result:selected, .overview-tile:checked, .grid-search-result:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #262626; }
++    background-color: st-mix(st-lighten(#000000, 8%), #ffffff, 87%); }
 +    .overview-tile:highlighted:hover, .grid-search-result:highlighted:hover, .overview-tile:selected:hover, .grid-search-result:selected:hover, .overview-tile:checked:hover, .grid-search-result:checked:hover {
-       background-color: #2b2b2b; }
++      background-color: st-lighten(st-lighten(#000000, 8%), 7%); }
 +    .overview-tile:highlighted:active, .grid-search-result:highlighted:active, .overview-tile:selected:active, .grid-search-result:selected:active, .overview-tile:checked:active, .grid-search-result:checked:active {
-     color: rgba(255, 255, 255, 0.5);
++      background-color: st-lighten(st-lighten(#000000, 8%), 9%); }
 +  .overview-tile:insensitive, .grid-search-result:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: rgba(53, 132, 228, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++    color: st-transparentize(#ffffff, 0.5);
 +    background-color: #000000;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .overview-tile:drop, .grid-search-result:drop {
-   background-color: #353535; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +  .overview-tile .overview-icon.overview-icon-with-label > StBoxLayout, .grid-search-result .overview-icon.overview-icon-with-label > StBoxLayout {
 +    spacing: 6px; }
 +
 +.app-folder {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #35393e; }
++  background-color: st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%); }
 +  .app-folder:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #3e4246; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%), 5%); }
 +    .app-folder:focus:hover {
-     background-color: #3e3e3e; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 4%), #ffffff, 87%), 5%); }
 +  .app-folder:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #494949; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 4%), #ffffff, 87%); }
 +  .app-folder:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #383838; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%); }
 +    .app-folder:active:hover {
-       background-color: #484c51; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), 4%); }
 +    .app-folder:active:focus {
-     background-color: #474747; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%), 5%); }
 +  .app-folder:highlighted, .app-folder:selected, .app-folder:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #363636; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 8%), #ffffff, 87%); }
 +    .app-folder:highlighted:hover, .app-folder:selected:hover, .app-folder:checked:hover {
-       background-color: #424242; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 8%), 4%); }
 +    .app-folder:highlighted:active, .app-folder:selected:active, .app-folder:checked:active {
-     color: rgba(255, 255, 255, 0.5);
-     background-color: #0f0f0f;
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 8%), 9%); }
 +  .app-folder:insensitive {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-     background-color: rgba(53, 132, 228, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++    color: st-transparentize(#ffffff, 0.5);
++    background-color: st-darken(st-mix(#ffffff, #000000, 9%), 3%);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +  .app-folder:drop {
-     background-color: #535353; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.app-grid-running-dot {
 +  height: 5px;
 +  width: 5px;
 +  border-radius: 5px;
 +  background-color: #ffffff;
 +  offset-y: 6px; }
 +
 +.app-folder-dialog-container {
 +  padding-top: 2.2em; }
 +
 +.app-folder-dialog {
 +  width: 720px;
 +  height: 720px;
 +  border-radius: 64px;
 +  background-color: #252525;
 +  color: #ffffff;
 +  padding: 0 2px;
 +  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.4); }
 +  .app-folder-dialog .folder-name-container {
 +    padding: 24px 36px;
 +    padding-bottom: 0; }
 +    .app-folder-dialog .folder-name-container .folder-name-entry {
 +      width: 12em; }
 +  .app-folder-dialog .icon-button, .app-folder-dialog .login-dialog-button.cancel-button, .app-folder-dialog .login-dialog-button.switch-user-button, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button, .app-folder-dialog .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .app-folder-dialog .pager-button, .app-folder-dialog .message .message-header .message-expand-button, .message .message-header .app-folder-dialog .message-expand-button,
 +  .app-folder-dialog .message .message-header .message-close-button,
 +  .message .message-header .app-folder-dialog .message-close-button, .app-folder-dialog .screenshot-ui-show-pointer-button {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #5c5c5c; }
++    background-color: st-mix(st-mix(#ffffff, #252525, 9%), #ffffff, 87%); }
 +    .app-folder-dialog .icon-button:hover, .app-folder-dialog .login-dialog-button.cancel-button:hover, .app-folder-dialog .login-dialog-button.switch-user-button:hover, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:hover, .app-folder-dialog .calendar .calendar-month-header .pager-button:hover, .calendar .calendar-month-header .app-folder-dialog .pager-button:hover, .app-folder-dialog .message .message-header .message-expand-button:hover, .message .message-header .app-folder-dialog .message-expand-button:hover,
 +    .app-folder-dialog .message .message-header .message-close-button:hover,
 +    .message .message-header .app-folder-dialog .message-close-button:hover, .app-folder-dialog .screenshot-ui-show-pointer-button:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #676767; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #252525, 9%), 4%), #ffffff, 87%); }
 +    .app-folder-dialog .icon-button:active, .app-folder-dialog .login-dialog-button.cancel-button:active, .app-folder-dialog .login-dialog-button.switch-user-button:active, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active, .app-folder-dialog .calendar .calendar-month-header .pager-button:active, .calendar .calendar-month-header .app-folder-dialog .pager-button:active, .app-folder-dialog .message .message-header .message-expand-button:active, .message .message-header .app-folder-dialog .message-expand-button:active,
 +    .app-folder-dialog .message .message-header .message-close-button:active,
 +    .message .message-header .app-folder-dialog .message-close-button:active, .app-folder-dialog .screenshot-ui-show-pointer-button:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #5a5a5a; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #252525, 9%), 9%), #ffffff, 87%); }
 +      .app-folder-dialog .icon-button:active:hover, .app-folder-dialog .login-dialog-button.cancel-button:active:hover, .app-folder-dialog .login-dialog-button.switch-user-button:active:hover, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active:hover, .app-folder-dialog .calendar .calendar-month-header .pager-button:active:hover, .calendar .calendar-month-header .app-folder-dialog .pager-button:active:hover, .app-folder-dialog .message .message-header .message-expand-button:active:hover, .message .message-header .app-folder-dialog .message-expand-button:active:hover,
 +      .app-folder-dialog .message .message-header .message-close-button:active:hover,
 +      .message .message-header .app-folder-dialog .message-close-button:active:hover, .app-folder-dialog .screenshot-ui-show-pointer-button:active:hover {
-         background-color: #65686d; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #252525, 9%), 9%), 4%); }
 +      .app-folder-dialog .icon-button:active:focus, .app-folder-dialog .login-dialog-button.cancel-button:active:focus, .app-folder-dialog .login-dialog-button.switch-user-button:active:focus, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active:focus, .app-folder-dialog .calendar .calendar-month-header .pager-button:active:focus, .calendar .calendar-month-header .app-folder-dialog .pager-button:active:focus, .app-folder-dialog .message .message-header .message-expand-button:active:focus, .message .message-header .app-folder-dialog .message-expand-button:active:focus,
 +      .app-folder-dialog .message .message-header .message-close-button:active:focus,
 +      .message .message-header .app-folder-dialog .message-close-button:active:focus, .app-folder-dialog .screenshot-ui-show-pointer-button:active:focus {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #252525, 9%), 9%), #ffffff, 87%), 5%); }
 +  .app-folder-dialog .page-indicators {
 +    margin-bottom: 24px; }
 +  .app-folder-dialog .page-navigation-arrow {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
 +    background-color: #252525;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +    .app-folder-dialog .page-navigation-arrow:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #555555; }
++      background-color: st-mix(st-lighten(#252525, 7%), #ffffff, 87%); }
 +    .app-folder-dialog .page-navigation-arrow:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #4e4e4e; }
++      background-color: st-mix(st-lighten(#252525, 9%), #ffffff, 87%); }
 +      .app-folder-dialog .page-navigation-arrow:active:hover {
-         background-color: #53575c; }
++        background-color: st-lighten(st-lighten(#252525, 9%), 7%); }
 +      .app-folder-dialog .page-navigation-arrow:active:focus {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-       background-color: rgba(41, 63, 88, 0.2875); }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 9%), #ffffff, 87%), 5%); }
 +  .app-folder-dialog .overview-tile, .app-folder-dialog .grid-search-result {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
 +    background-color: #252525;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    box-shadow: none;
 +    border: none; }
 +    .app-folder-dialog .overview-tile:focus, .app-folder-dialog .grid-search-result:focus {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #505458; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++      background-color: st-mix(-st-accent-color, rgba(37, 37, 37, 0.25), 5%); }
 +      .app-folder-dialog .overview-tile:focus:hover, .app-folder-dialog .grid-search-result:focus:hover {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 7%), #ffffff, 87%), 5%); }
 +    .app-folder-dialog .overview-tile:hover, .app-folder-dialog .grid-search-result:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #555555; }
++      background-color: st-mix(st-lighten(#252525, 7%), #ffffff, 87%); }
 +    .app-folder-dialog .overview-tile:active, .app-folder-dialog .grid-search-result:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #4e4e4e; }
++      background-color: st-mix(st-lighten(#252525, 9%), #ffffff, 87%); }
 +      .app-folder-dialog .overview-tile:active:hover, .app-folder-dialog .grid-search-result:active:hover {
-         background-color: #53575c; }
++        background-color: st-lighten(st-lighten(#252525, 9%), 7%); }
 +      .app-folder-dialog .overview-tile:active:focus, .app-folder-dialog .grid-search-result:active:focus {
-       background-color: #535353; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(#252525, 9%), #ffffff, 87%), 5%); }
 +    .app-folder-dialog .overview-tile:highlighted, .app-folder-dialog .grid-search-result:highlighted, .app-folder-dialog .overview-tile:selected, .app-folder-dialog .grid-search-result:selected, .app-folder-dialog .overview-tile:checked, .app-folder-dialog .grid-search-result:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #4b4b4b; }
++      background-color: st-mix(st-lighten(#252525, 8%), #ffffff, 87%); }
 +      .app-folder-dialog .overview-tile:highlighted:hover, .app-folder-dialog .grid-search-result:highlighted:hover, .app-folder-dialog .overview-tile:selected:hover, .app-folder-dialog .grid-search-result:selected:hover, .app-folder-dialog .overview-tile:checked:hover, .app-folder-dialog .grid-search-result:checked:hover {
-         background-color: #505050; }
++        background-color: st-lighten(st-lighten(#252525, 8%), 7%); }
 +      .app-folder-dialog .overview-tile:highlighted:active, .app-folder-dialog .grid-search-result:highlighted:active, .app-folder-dialog .overview-tile:selected:active, .app-folder-dialog .grid-search-result:selected:active, .app-folder-dialog .overview-tile:checked:active, .app-folder-dialog .grid-search-result:checked:active {
-       color: rgba(255, 255, 255, 0.5);
++        background-color: st-lighten(st-lighten(#252525, 8%), 9%); }
 +    .app-folder-dialog .overview-tile:insensitive, .app-folder-dialog .grid-search-result:insensitive {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-       background-color: rgba(53, 132, 228, 0.2);
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8); }
++      color: st-transparentize(#ffffff, 0.5);
 +      background-color: #252525;
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      box-shadow: none;
 +      border: none; }
 +    .app-folder-dialog .overview-tile:drop, .app-folder-dialog .grid-search-result:drop {
-     background-color: #313131; }
++      background-color: st-transparentize(-st-accent-color, 0.8);
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.rename-folder-popup .rename-folder-popup-item {
 +  spacing: 6px; }
 +  .rename-folder-popup .rename-folder-popup-item:ltr, .rename-folder-popup .rename-folder-popup-item:rtl {
 +    padding: 0 12px; }
 +
 +.page-indicator {
 +  padding: 6px 12px 0;
 +  transition-duration: 400ms; }
 +  .page-indicator .page-indicator-icon {
 +    width: 10px;
 +    height: 10px;
 +    border-radius: 999px;
 +    background-color: #ffffff;
 +    transition-duration: 400ms; }
 +
 +.apps-scroll-view {
 +  padding: 0; }
 +
 +.system-action-icon {
 +  background-color: rgba(255, 255, 255, 0.1);
 +  color: #ffffff;
 +  border-radius: 999px;
 +  icon-size: 48px;
 +  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.4); }
 +
 +.page-navigation-hint.dnd {
 +  background: rgba(255, 255, 255, 0.1); }
 +
 +.page-navigation-hint.next:ltr, .page-navigation-hint.previous:rtl {
 +  background-gradient-start: rgba(255, 255, 255, 0.05);
 +  background-gradient-end: transparent;
 +  background-gradient-direction: horizontal;
 +  border-radius: 24px 0px 0px 24px; }
 +
 +.page-navigation-hint.previous:ltr, .page-navigation-hint.next:rtl {
 +  background-gradient-start: transparent;
 +  background-gradient-end: rgba(255, 255, 255, 0.05);
 +  background-gradient-direction: horizontal;
 +  border-radius: 0px 24px 24px 0px; }
 +
 +.page-navigation-arrow {
 +  margin: 6px;
 +  padding: 18px;
 +  width: 24px;
 +  height: 24px;
 +  border-radius: 999px;
 +  transition-duration: 100ms;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
 +  background-color: #000000;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none; }
 +  .page-navigation-arrow > StIcon {
 +    color: #ffffff; }
 +  .page-navigation-arrow:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #353535; }
++    background-color: st-mix(st-lighten(#000000, 7%), #ffffff, 87%); }
 +  .page-navigation-arrow:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #292929; }
++    background-color: st-mix(st-lighten(#000000, 9%), #ffffff, 87%); }
 +    .page-navigation-arrow:active:hover {
-       background-color: #35393e; }
++      background-color: st-lighten(st-lighten(#000000, 9%), 7%); }
 +    .page-navigation-arrow:active:focus {
-   border: 3px solid #3584e4;
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 9%), #ffffff, 87%), 5%); }
 +
 +/* Workspace pager */
 +.workspace-thumbnails {
 +  visible-width: 32px;
 +  spacing: 6px;
 +  padding: 6px; }
 +  .workspace-thumbnails .workspace-thumbnail {
 +    color: #ffffff;
 +    background-color: #262626;
 +    border-radius: 4px;
 +    border: 1px solid transparent;
 +    border-color: rgba(255, 255, 255, 0.4); }
 +  .workspace-thumbnails .placeholder {
 +    background-image: url("resource:///org/gnome/shell/theme/workspace-placeholder.svg");
 +    background-size: contain;
 +    width: 18px; }
 +
 +.workspace-thumbnail-indicator {
-   background-color: rgba(188, 214, 246, 0.3);
-   box-shadow: 0 0 2px 2px #8fbbf0; }
++  border: 3px solid -st-accent-color;
 +  border-radius: 8px; }
 +
 +.ripple-pointer-location {
 +  width: 50px;
 +  height: 50px;
 +  border-radius: 25px;
-   -pie-border-color: #3584e4;
-   -pie-background-color: rgba(233, 242, 252, 0.3); }
++  background-color: st-lighten(st-transparentize(-st-accent-color, 0.7), 30%);
++  box-shadow: 0 0 2px 2px st-lighten(-st-accent-color, 20%); }
 +
 +.pie-timer {
 +  width: 60px;
 +  height: 60px;
 +  -pie-border-width: 3px;
-   border: 2px solid #3584e4; }
++  -pie-border-color: -st-accent-color;
++  -pie-background-color: st-lighten(st-transparentize(-st-accent-color, 0.7), 40%); }
 +
 +.magnifier-zoom-region {
-   background-color: rgba(53, 132, 228, 0.3);
-   border: 1px solid #3584e4; }
++  border: 2px solid -st-accent-color; }
 +  .magnifier-zoom-region.full-screen {
 +    border-width: 0; }
 +
 +.select-area-rubberband {
-   background-color: rgba(53, 132, 228, 0.5);
-   border: 1px solid #3584e4; }
++  background-color: st-transparentize(-st-accent-color, 0.7);
++  border: 1px solid -st-accent-color; }
 +
 +.user-icon {
 +  background-size: contain;
 +  border-radius: 999px;
 +  icon-size: 64px;
 +  background-color: rgba(255, 255, 255, 0.05);
 +  color: #ffffff; }
 +  .user-icon StIcon {
 +    padding: 12px; }
 +  .user-icon.user-avatar {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
 +
 +.lightbox {
 +  background-color: black; }
 +
 +.flashspot {
 +  background-color: white; }
 +
 +.hidden {
 +  color: transparent; }
 +
 +.caps-lock-warning-label {
 +  text-align: center;
 +  padding-bottom: 8px;
 +  color: #f6d32d; }
 +
 +/* Workspace animation */
 +.workspace-animation {
 +  background-color: #0d0d0d; }
 +
 +/* Tiled window previews */
 +.tile-preview {
-   background-color: #727272; }
++  background-color: st-transparentize(-st-accent-color, 0.5);
++  border: 1px solid -st-accent-color; }
 +
 +/* On-screen Keyboard */
 +#keyboard {
 +  background-color: #000000;
 +  box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.2); }
 +  #keyboard .page-indicator {
 +    padding: 6px; }
 +    #keyboard .page-indicator .page-indicator-icon {
 +      width: 8px;
 +      height: 8px; }
 +
 +.key-container {
 +  padding: 4px;
 +  spacing: 4px; }
 +
 +.keyboard-key {
 +  font-size: 1.455em;
 +  font-weight: bold;
 +  min-height: 1.2em;
 +  min-width: 1.2em;
 +  border-width: 1px;
 +  border-style: solid;
 +  border-radius: 10px;
 +  box-shadow: 0 1px 0 0 transparent;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: #484c51; }
++  background-color: st-mix(st-mix(#ffffff, #4d4d4d, 9%), #ffffff, 87%); }
 +  .keyboard-key:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #515559; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%), 5%); }
 +    .keyboard-key:focus:hover {
-     background-color: #7b7b7b; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 4%), #ffffff, 87%), 5%); }
 +  .keyboard-key:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #868686; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 4%), #ffffff, 87%); }
 +  .keyboard-key:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #7e7e7e; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), #ffffff, 87%); }
 +    .keyboard-key:active:hover {
-       background-color: #82868b; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 4%); }
 +    .keyboard-key:active:focus {
-     background-color: #848484; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), #ffffff, 87%), 5%); }
 +  .keyboard-key:checked {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #7c7c7c; }
++    background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), #ffffff, 87%); }
 +    .keyboard-key:checked:hover {
-       background-color: #888888; }
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 4%); }
 +    .keyboard-key:checked:active {
-     background-color: #5d5d5d;
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 9%); }
 +  .keyboard-key:grayed {
 +    background-color: #121212;
 +    color: #ffffff;
 +    border-color: rgba(255, 255, 255, 0.2); }
 +  .keyboard-key.default-key {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #666666; }
++    background-color: st-mix(st-mix(#ffffff, #333333, 9%), #ffffff, 87%);
 +    border-radius: 10px; }
 +    .keyboard-key.default-key:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #717171; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #333333, 9%), 4%), #ffffff, 87%); }
 +    .keyboard-key.default-key:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #666666; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #333333, 9%), 9%), #ffffff, 87%); }
 +      .keyboard-key.default-key:active:hover {
-         background-color: #6e7277; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #333333, 9%), 9%), 4%); }
 +      .keyboard-key.default-key:active:focus {
-       background-color: #6f6f6f; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #333333, 9%), 9%), #ffffff, 87%), 5%); }
 +    .keyboard-key.default-key:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #646464; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #333333, 9%), 8%), #ffffff, 87%); }
 +      .keyboard-key.default-key:checked:hover {
-         background-color: #707070; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #333333, 9%), 8%), 4%); }
 +      .keyboard-key.default-key:checked:active {
-       border-color: #4b92e7;
-       background-color: #3584e4; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #333333, 9%), 8%), 9%); }
 +    .keyboard-key.default-key:latched {
-     color: #ffffff;
-     background-color: #5f9ee9;
++      border-color: st-lighten(-st-accent-color, 5%);
++      background-color: -st-accent-color; }
 +  .keyboard-key.enter-key {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-       color: #ffffff;
-       background-color: #6fa7eb; }
++    color: -st-accent-fg-color;
++    background-color: st-mix(st-mix(-st-accent-fg-color, -st-accent-color, 9%), #ffffff, 87%);
 +    border-radius: 10px;
 +    color: #ffffff; }
 +    .keyboard-key.enter-key:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-       color: #ffffff;
-       background-color: #82b3ee; }
++      color: -st-accent-fg-color;
++      background-color: st-mix(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 4%), #ffffff, 87%); }
 +    .keyboard-key.enter-key:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-         background-color: #81b3ee; }
++      color: -st-accent-fg-color;
++      background-color: st-mix(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 9%), #ffffff, 87%); }
 +      .keyboard-key.enter-key:active:hover {
-         background-color: #7eb1ee; }
++        background-color: st-lighten(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 9%), 4%); }
 +      .keyboard-key.enter-key:active:focus {
-       color: #ffffff;
-       background-color: #7eb1ed; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 9%), #ffffff, 87%), 5%); }
 +    .keyboard-key.enter-key:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
-         background-color: #7db0ed; }
++      color: -st-accent-fg-color;
++      background-color: st-mix(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 8%), #ffffff, 87%); }
 +      .keyboard-key.enter-key:checked:hover {
-         background-color: #93bdf0; }
++        background-color: st-lighten(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 8%), 4%); }
 +      .keyboard-key.enter-key:checked:active {
-     background-color: #727272;
++        background-color: st-lighten(st-lighten(st-mix(-st-accent-fg-color, -st-accent-color, 9%), 8%), 9%); }
 +  .keyboard-key.shift-key-uppercase {
 +    background-color: gray;
 +    color: #000000; }
 +    .keyboard-key.shift-key-uppercase:hover {
 +      background-color: #8c8c8c;
 +      color: #0d0d0d; }
 +  .keyboard-key StIcon {
 +    icon-size: 24px; }
 +
 +.keyboard-subkeys {
 +  -arrow-border-radius: 16px;
 +  -arrow-background-color: #000000;
 +  -arrow-border-width: 1px;
 +  -arrow-border-color: #171717;
 +  -arrow-base: 20px;
 +  -arrow-rise: 10px;
 +  -boxpointer-gap: 6px;
 +  padding: 6px; }
 +  .keyboard-subkeys .keyboard-key {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-       background-color: #484c51; }
++    background-color: st-mix(st-mix(#ffffff, #4d4d4d, 9%), #ffffff, 87%);
 +    border-radius: 10px; }
 +    .keyboard-subkeys .keyboard-key:focus {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #515559; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++      background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%), 5%); }
 +      .keyboard-subkeys .keyboard-key:focus:hover {
-       background-color: #7b7b7b; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 4%), #ffffff, 87%), 5%); }
 +    .keyboard-subkeys .keyboard-key:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #868686; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 4%), #ffffff, 87%); }
 +    .keyboard-subkeys .keyboard-key:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #7e7e7e; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), #ffffff, 87%); }
 +      .keyboard-subkeys .keyboard-key:active:hover {
-         background-color: #82868b; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 4%); }
 +      .keyboard-subkeys .keyboard-key:active:focus {
-       background-color: #848484; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), #ffffff, 87%), 5%); }
 +    .keyboard-subkeys .keyboard-key:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #7c7c7c; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), #ffffff, 87%); }
 +      .keyboard-subkeys .keyboard-key:checked:hover {
-         background-color: #888888; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 4%); }
 +      .keyboard-subkeys .keyboard-key:checked:active {
-   border-color: #4b92e7;
-   background-color: #3584e4; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 9%); }
 +
 +.emoji-page .keyboard-key {
 +  background-color: transparent;
 +  border: none;
 +  color: initial; }
 +
 +.emoji-panel .keyboard-key:latched {
-       box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-       background-color: #484c51; }
++  border-color: st-lighten(-st-accent-color, 5%);
++  background-color: -st-accent-color; }
 +
 +.word-suggestions {
 +  spacing: 12px;
 +  min-height: 17pt;
 +  padding: 12px;
 +  color: #ffffff; }
 +  .word-suggestions StButton {
 +    margin: 0 3px;
 +    min-width: 32px;
 +    border-radius: 4px;
 +    padding: 0px 18px;
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    background-color: transparent;
 +    border-color: transparent;
 +    box-shadow: none; }
 +    .word-suggestions StButton:insensitive {
 +      background-color: transparent !important; }
 +    .word-suggestions StButton:focus {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #515559; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++      background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #1a1a1a, 9%), #ffffff, 87%), 5%); }
 +      .word-suggestions StButton:focus:hover {
-       background-color: #7b7b7b; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #1a1a1a, 9%), 4%), #ffffff, 87%), 5%); }
 +    .word-suggestions StButton:hover {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-       background-color: #868686; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 4%), #ffffff, 87%); }
 +    .word-suggestions StButton:active {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #7e7e7e; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), #ffffff, 87%); }
 +      .word-suggestions StButton:active:hover {
-         background-color: #82868b; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), 4%); }
 +      .word-suggestions StButton:active:focus {
-       background-color: #848484; }
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 9%), #ffffff, 87%), 5%); }
 +    .word-suggestions StButton:checked {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         background-color: #7c7c7c; }
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), #ffffff, 87%); }
 +      .word-suggestions StButton:checked:hover {
-         background-color: #888888; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 4%); }
 +      .word-suggestions StButton:checked:active {
-   #LookingGlassDialog StBoxLayout#EvalBox {
-     padding: 4px;
-     spacing: 6px;
-     padding: 6px; }
-   #LookingGlassDialog StBoxLayout#ResultsArea {
-     spacing: 6px;
-     padding: 6px; }
- 
- .lg-dialog StEntry {
-   min-height: 1.5em; }
- 
- .lg-dialog .shell-link {
-   color: #62a0ea; }
-   .lg-dialog .shell-link:hover {
-     color: #8fbbf0; }
-   .lg-dialog .shell-link:active {
-     color: #3585e4; }
- 
- .lg-dialog .actor-link {
-   color: #ffffff; }
-   .lg-dialog .actor-link:hover {
-     color: white; }
-   .lg-dialog .actor-link:active {
-     color: #cccccc; }
-   .lg-dialog .actor-link StIcon {
-     icon-size: 12px; }
- 
- .lg-completions-text {
-   font-style: italic; }
- 
- .lg-obj-inspector-title {
-   spacing: 6px; }
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #4d4d4d, 9%), 8%), 9%); }
 +
 +/* Looking Glass */
++.lg-dialog StEntry {
++  min-height: 1.5em; }
++
++.lg-dialog .shell-link {
++  color: st-lighten(-st-accent-color, 20%); }
++  .lg-dialog .shell-link:hover {
++    color: st-lighten(st-lighten(-st-accent-color, 20%), 10%); }
++  .lg-dialog .shell-link:active {
++    color: st-darken(st-lighten(-st-accent-color, 20%), 10%); }
++
++.lg-dialog .actor-link {
++  color: st-darken(#ffffff, 20%); }
++  .lg-dialog .actor-link:hover {
++    color: #ffffff; }
++  .lg-dialog .actor-link:active {
++    color: st-lighten(#ffffff, 20%); }
++  .lg-dialog .actor-link StIcon {
++    icon-size: 12px; }
++
++.lg-completions-text {
++  font-style: italic; }
++
 +#LookingGlassDialog {
 +  background-color: rgba(0, 0, 0, 0.98);
 +  color: #ffffff;
 +  border-radius: 16px;
 +  margin-top: 4px;
 +  border: 2px solid transparent;
 +  padding: 6px;
 +  spacing: 6px;
 +  box-shadow: 0 2px 4px 0 transparent;
 +  border-color: rgba(255, 255, 255, 0.4);
 +  background-color: #000000;
 +  box-shadow: none; }
 +  #LookingGlassDialog > #Toolbar {
 +    border: none;
 +    padding: 6px;
 +    border-radius: 0;
 +    background-color: transparent;
 +    spacing: 6px; }
 +    #LookingGlassDialog > #Toolbar .lg-toolbar-button {
 +      padding: 6px 12px; }
 +      #LookingGlassDialog > #Toolbar .lg-toolbar-button > StIcon {
 +        icon-size: 16px; }
 +  #LookingGlassDialog .labels {
 +    spacing: 6px; }
 +  #LookingGlassDialog .notebook-tab {
++    background-color: transparent;
 +    -natural-hpadding: 12px;
 +    -minimum-hpadding: 12px;
 +    padding: 6px 12px; }
- .lg-obj-inspector-button {
-   border: 1px solid rgba(255, 255, 255, 0.5);
-   padding: 4px;
-   border-radius: 8px; }
-   .lg-obj-inspector-button:hover {
-     border: 1px solid #ffffff; }
++    #LookingGlassDialog .notebook-tab:selected {
++      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++      color: #ffffff;
++      background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%); }
++      #LookingGlassDialog .notebook-tab:selected:hover {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), 4%); }
++      #LookingGlassDialog .notebook-tab:selected:focus {
++        background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%), 5%); }
 +
- #lookingGlassExtensions {
++#LookingGlassPropertyInspector {
++  background-color: #000000;
++  color: #ffffff;
++  border-radius: 16px;
++  border: 1px solid rgba(255, 255, 255, 0.2);
++  padding: 12px;
++  border-color: rgba(255, 255, 255, 0.4); }
++  #LookingGlassPropertyInspector .lg-obj-inspector-title {
++    spacing: 4px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button {
++    padding: 6px 12px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-close-button {
++    margin: 4px;
++    padding: 6px;
++    border-radius: 999px; }
++    #LookingGlassPropertyInspector .lg-obj-inspector-close-button > StIcon {
++      icon-size: 16px; }
 +
- .lg-extensions-list {
++#LookingGlassEvaluator {
 +  padding: 6px; }
++  #LookingGlassEvaluator .evaluator-results {
++    spacing: 6px; }
 +
- .lg-extension-meta {
++#LookingGlassWindows {
 +  padding: 6px;
 +  spacing: 6px; }
++  #LookingGlassWindows .lg-window {
++    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++    color: #ffffff;
++    background-color: st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%);
++    margin: 0;
++    padding: 12px; }
 +
- #LookingGlassPropertyInspector {
-   background: #1a1a1a;
-   border: 1px solid rgba(255, 255, 255, 0.5);
-   border-radius: 8px;
-   padding: 6px; }
++#LookingGlassExtensions .lg-extensions-list {
++  padding: 6px;
 +  spacing: 6px; }
 +
- .lg-debug-flag-button {
-   color: #ffffff; }
-   .lg-debug-flag-button StLabel {
-     padding: 6px, 12px; }
-   .lg-debug-flag-button:hover {
-     color: white; }
-   .lg-debug-flag-button:active {
-     color: #cccccc; }
++#LookingGlassExtensions .lg-extension {
++  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
++  color: #ffffff;
++  background-color: st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%);
++  margin: 0;
++  spacing: 4px;
++  padding: 12px; }
++  #LookingGlassExtensions .lg-extension .lg-extension-name {
++    color: #ffffff !important; }
++  #LookingGlassExtensions .lg-extension .lg-extension-meta {
++    spacing: 12px; }
 +
- .lg-debug-flags-header {
-   padding-top: 12px;
-   padding: 6px; }
++#LookingGlassExtensions .lg-extensions-none {
++  color: rgba(255, 255, 255, 0.5); }
 +
-     box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-     background-color: rgba(14, 36, 61, 0.2875); }
++#LookingGlassActors {
++  padding: 6px;
++  spacing: 4px; }
++
++#LookingGlassDebugFlags .lg-debug-flags-header {
++  padding: 6px;
++  padding-top: 12px; }
++
++#LookingGlassDebugFlags .lg-debug-flag-button {
++  padding: 9px 12px;
++  margin-bottom: 6px; }
++  #LookingGlassDebugFlags .lg-debug-flag-button StLabel {
++    font-weight: normal !important; }
++  #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch {
++    background: rgba(255, 255, 255, 0.3); }
++    #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:hover {
++      background: rgba(255, 255, 255, 0.4); }
++    #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:checked {
++      background: -st-accent-color;
++      color: -st-accent-fg-color; }
++      #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:checked:hover {
++        background-color: st-lighten(-st-accent-color, 5%);
++        color: st-lighten(-st-accent-fg-color, 5%); }
 +
 +.login-dialog,
 +.unlock-dialog {
 +  color: #ffffff; }
 +  .login-dialog .caps-lock-warning-label,
 +  .login-dialog .login-dialog-message-warning,
 +  .unlock-dialog .caps-lock-warning-label,
 +  .unlock-dialog .login-dialog-message-warning {
 +    color: #ffffff; }
 +  .login-dialog .login-dialog-prompt-layout,
 +  .unlock-dialog .login-dialog-prompt-layout {
 +    width: 25em;
 +    spacing: 9px; }
 +
 +.login-dialog-button.cancel-button {
 +  padding: 9px; }
 +
 +.login-dialog-button-box {
 +  spacing: 12px; }
 +
 +.conflicting-session-dialog-content {
 +  spacing: 20px; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-title {
 +    text-align: center;
 +    margin-bottom: 5px; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-desc {
 +    text-align: center; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-desc-warning {
 +    text-align: center;
 +    color: #f6d32d; }
 +
 +.login-dialog-logo-bin {
 +  margin: 3em 0; }
 +
 +.login-dialog-banner-view {
 +  max-width: 25em; }
 +  .login-dialog-banner-view .login-dialog-banner {
 +    color: #e6e6e6; }
 +
 +.login-dialog-message {
 +  text-align: center; }
 +
 +.login-dialog-message-hint, .login-dialog-message {
 +  color: #e6e6e6;
 +  min-height: 2.75em; }
 +
 +.login-dialog-user-selection-box {
 +  padding-top: 4em;
 +  padding-bottom: 8em; }
 +
 +.login-dialog-not-listed-label {
 +  padding: 6px; }
 +
 +.login-dialog-not-listed-button {
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  color: #ffffff;
 +  background-color: #000000;
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +  box-shadow: none;
 +  border: none;
 +  padding: 0 6px;
 +  margin: 6px; }
 +  .login-dialog-not-listed-button:focus {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #31353a; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++    background-color: st-mix(-st-accent-color, rgba(0, 0, 0, 0.25), 5%); }
 +    .login-dialog-not-listed-button:focus:hover {
-     background-color: #313131; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 7%), #ffffff, 87%), 5%); }
 +  .login-dialog-not-listed-button:hover {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-     background-color: #353535; }
++    background-color: st-mix(st-lighten(#000000, 7%), #ffffff, 87%); }
 +  .login-dialog-not-listed-button:active {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +    color: #ffffff;
-       background-color: #292929; }
++    background-color: st-mix(st-lighten(#000000, 9%), #ffffff, 87%); }
 +    .login-dialog-not-listed-button:active:hover {
-       background-color: #35393e; }
++      background-color: st-lighten(st-lighten(#000000, 9%), 7%); }
 +    .login-dialog-not-listed-button:active:focus {
-     background-color: #3584e4;
-     color: #ffffff; }
++      background-color: st-mix(-st-accent-color, st-mix(st-lighten(#000000, 9%), #ffffff, 87%), 5%); }
 +
 +.login-dialog-auth-list-view {
 +  -st-vfade-offset: 3em; }
 +
 +.login-dialog-auth-list {
 +  spacing: 6px;
 +  margin-left: 2em; }
 +
 +.login-dialog-auth-list-title {
 +  margin-left: 2em; }
 +
 +.login-dialog-auth-list-item {
 +  border-radius: 16px;
 +  padding: 4px;
 +  color: #b3b3b3; }
 +  .login-dialog-auth-list-item:focus, .login-dialog-auth-list-item:selected {
-       background-color: #353535;
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +
 +.login-dialog-auth-list-label:ltr {
 +  padding-left: 15px;
 +  text-align: left; }
 +
 +.login-dialog-auth-list-label:rtl {
 +  padding-right: 15px;
 +  text-align: right; }
 +
 +.login-dialog-user-list-view {
 +  width: 25em;
 +  -st-vfade-offset: 3em; }
 +  .login-dialog-user-list-view .login-dialog-user-list {
 +    margin: 0 8px;
 +    spacing: 12px; }
 +    .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item {
 +      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +      color: #ffffff;
-         box-shadow: inset 0 0 0 2px rgba(53, 132, 228, 0.8) !important;
-         background-color: #35393e; }
++      background-color: st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%);
 +      border-radius: 16px;
 +      padding: 9px; }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:selected, .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:focus {
 +        box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +        color: #ffffff;
-           background-color: #3e4246; }
++        box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2) !important;
++        background-color: st-mix(-st-accent-color, st-mix(st-mix(#ffffff, #000000, 9%), #ffffff, 87%), 5%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:selected:hover, .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:focus:hover {
-         background-color: #3e3e3e; }
++          background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 4%), #ffffff, 87%), 5%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:hover {
 +        box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +        color: #ffffff;
-         background-color: #494949; }
++        background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 4%), #ffffff, 87%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active {
 +        box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
 +        color: #ffffff;
-           background-color: #383838; }
++        background-color: st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active:hover {
-           background-color: #484c51; }
++          background-color: st-lighten(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), 4%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active:focus {
-         border-color: #3584e4; }
++          background-color: st-mix(-st-accent-color, st-mix(st-lighten(st-mix(#ffffff, #000000, 9%), 9%), #ffffff, 87%), 5%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item .user-icon {
 +        border: 2px solid transparent; }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item .login-dialog-timed-login-indicator {
 +        height: 2px;
 +        margin-top: 6px;
 +        background-color: rgba(255, 255, 255, 0.7); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:logged-in .user-icon {
-           background-color: rgba(53, 132, 228, 0.3); }
++        border-color: -st-accent-color; }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:logged-in .user-icon StIcon {
-     font-weight: 200; }
++          background-color: st-transparentize(-st-accent-color, 0.7); }
 +
 +.unlock-dialog {
 +  background-color: transparent; }
 +
 +.screen-shield-background {
 +  background: black;
 +  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6); }
 +
 +#lockDialogGroup {
 +  background-color: #000000; }
 +
 +.unlock-dialog-clock {
 +  color: #ffffff;
 +  spacing: 2em; }
 +  .unlock-dialog-clock .unlock-dialog-clock-time {
 +    font-size: 6.546em;
-     background-color: rgba(53, 132, 228, 0.5); }
++    font-weight: 800; }
 +  .unlock-dialog-clock .unlock-dialog-clock-date {
 +    font-weight: 400; }
 +  .unlock-dialog-clock .unlock-dialog-clock-hint {
 +    margin-top: 2em;
 +    padding: 6px 18px;
 +    border-radius: 16px;
 +    font-weight: bold; }
 +
 +#unlockDialogNotifications StButton#vhandle, #unlockDialogNotifications StButton#hhandle {
 +  background-color: rgba(26, 26, 26, 0.3); }
 +  #unlockDialogNotifications StButton#vhandle:hover, #unlockDialogNotifications StButton#vhandle:focus, #unlockDialogNotifications StButton#hhandle:hover, #unlockDialogNotifications StButton#hhandle:focus {
 +    background-color: rgba(26, 26, 26, 0.5); }
 +  #unlockDialogNotifications StButton#vhandle:active, #unlockDialogNotifications StButton#hhandle:active {
-       padding: 24px; }
++    background-color: st-transparentize(-st-accent-color, 0.5); }
 +
 +.unlock-dialog-notifications-container {
 +  margin: 12px;
 +  spacing: 6px;
 +  width: 25em;
 +  background-color: transparent; }
 +  .unlock-dialog-notifications-container .summary-notification-stack-scrollview {
 +    padding-top: 0;
 +    padding-bottom: 0; }
 +  .unlock-dialog-notifications-container .notification,
 +  .unlock-dialog-notifications-container .unlock-dialog-notification-source {
 +    padding: 12px 16px;
 +    border: none;
 +    background-color: rgba(255, 255, 255, 0.1);
 +    color: #ffffff;
 +    border-radius: 16px; }
 +    .unlock-dialog-notifications-container .notification.critical,
 +    .unlock-dialog-notifications-container .unlock-dialog-notification-source.critical {
 +      background-color: rgba(255, 255, 255, 0.2); }
 +
 +.unlock-dialog-notification-icon {
 +  icon-size: 32px; }
 +
 +.unlock-dialog-notification-label {
 +  padding-left: 12px;
 +  padding-right: 0; }
 +  .unlock-dialog-notification-label:rtl {
 +    padding-right: 12px;
 +    padding-left: 0; }
 +
 +.unlock-dialog-notification-count-text {
 +  font-weight: bold;
 +  padding: 0 12px;
 +  color: #ffffff;
 +  background-color: rgba(255, 255, 255, 0.1);
 +  border-radius: 999px; }
 +
 +.login-dialog .user-widget .user-widget-label,
 +.unlock-dialog .user-widget .user-widget-label {
 +  color: #ffffff; }
 +
 +.login-dialog .user-widget .user-icon,
 +.unlock-dialog .user-widget .user-icon {
 +  background-color: rgba(255, 255, 255, 0.13);
 +  color: #ffffff;
 +  background-color: rgba(255, 255, 255, 0.3);
 +  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
 +
 +.login-dialog .user-widget.horizontal,
 +.unlock-dialog .user-widget.horizontal {
 +  spacing: 18px; }
 +
 +.login-dialog .user-widget.vertical,
 +.unlock-dialog .user-widget.vertical {
 +  spacing: 24px; }
 +  .login-dialog .user-widget.vertical .user-widget-label,
 +  .unlock-dialog .user-widget.vertical .user-widget-label {
++    font-weight: 400;
++    font-size: 1.818em;
 +    text-align: center;
 +    margin-bottom: .75em; }
 +  .login-dialog .user-widget.vertical .user-icon,
 +  .unlock-dialog .user-widget.vertical .user-icon {
 +    icon-size: 160px; }
 +    .login-dialog .user-widget.vertical .user-icon StIcon,
 +    .unlock-dialog .user-widget.vertical .user-icon StIcon {
++      padding: 30px; }
index a9da1e650a5950afca952f1cb291cc5f2509082d,0000000000000000000000000000000000000000..a84dc2289d31bc43d850749e96c6edc95a3f8ad8
mode 100644,000000..100644
--- /dev/null
@@@ -1,3110 -1,0 +1,3219 @@@
- .unlock-dialog .screenshot-ui-show-pointer-button, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button, #LookingGlassDialog .notebook-tab, #LookingGlassDialog > #Toolbar .lg-toolbar-button, .icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .message .message-header .message-expand-button,
 +/* This stylesheet is generated, DO NOT EDIT */
 +/* Copyright 2009, 2015 Red Hat, Inc.
 + *
 + * Portions adapted from Mx's data/style/default.css
 + *   Copyright 2009 Intel Corporation
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms and conditions of the GNU Lesser General Public License,
 + * version 2.1, as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope it will be useful, but WITHOUT ANY
 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 + * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 + * more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +/* Global Values */
 +stage {
 +  font-size: 1em;
 +  color: #282828; }
 +
 +/* Common Stylings */
 +#dash .dash-item-container .show-apps,
 +#dash .dash-item-container .overview-tile,
 +#dash .dash-item-container .grid-search-result {
 +  background: none;
 +  box-shadow: none;
 +  border: none;
 +  border-radius: 0;
 +  padding: 0;
 +  margin: 0; }
 +
 +.app-folder-dialog .overview-tile, .app-folder-dialog .grid-search-result, .app-folder, .overview-tile, .grid-search-result, #dash .dash-item-container .show-apps .overview-icon,
 +#dash .dash-item-container .overview-tile .overview-icon,
 +#dash .dash-item-container .grid-search-result .overview-icon, .list-search-result, .search-provider-icon, .switcher-list .item-box {
 +  border-radius: 16px;
 +  padding: 6px;
 +  spacing: 6px;
 +  text-align: center;
 +  transition-duration: 100ms; }
 +
 +.login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item, .login-dialog-not-listed-button, .unlock-dialog .button,
 +.unlock-dialog .icon-button,
 +.unlock-dialog .message .message-header .message-expand-button,
 +.message .message-header .unlock-dialog .message-expand-button,
 +.unlock-dialog .message .message-header .message-close-button,
 +.message .message-header .unlock-dialog .message-close-button,
-   background-color: gainsboro; }
++.unlock-dialog .screenshot-ui-show-pointer-button, #LookingGlassDialog .notebook-tab, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button, #LookingGlassDebugFlags .lg-debug-flag-button, #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++#LookingGlassPropertyInspector .lg-obj-inspector-button, #LookingGlassDialog > #Toolbar .lg-toolbar-button, .icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button, .button {
 +  border-radius: 8px;
 +  padding: 3px 24px;
 +  font-weight: bold;
 +  transition: border-width 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); }
 +
 +.icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .screenshot-ui-show-pointer-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button, .button {
 +  color: #282828;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #d2d7dc; }
++  background-color: st-mix(#282828, whitesmoke, 12%); }
 +  .icon-button:focus, .login-dialog-button.cancel-button:focus, .login-dialog-button.switch-user-button:focus, .login-dialog-button.login-dialog-session-list-button:focus, .screenshot-ui-show-pointer-button:focus, .message .message-header .message-expand-button:focus,
 +  .message .message-header .message-close-button:focus, .calendar .calendar-month-header .pager-button:focus, .button:focus {
 +    color: #282828;
-       background-color: #c9cdd2; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#282828, whitesmoke, 12%), 5%); }
 +    .icon-button:focus:hover, .login-dialog-button.cancel-button:focus:hover, .login-dialog-button.switch-user-button:focus:hover, .login-dialog-button.login-dialog-session-list-button:focus:hover, .screenshot-ui-show-pointer-button:focus:hover, .message .message-header .message-expand-button:focus:hover,
 +    .message .message-header .message-close-button:focus:hover, .calendar .calendar-month-header .pager-button:focus:hover, .button:focus:hover {
-     background-color: #d2d2d2; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, whitesmoke, 12%), 4%), 5%); }
 +  .icon-button:hover, .login-dialog-button.cancel-button:hover, .login-dialog-button.switch-user-button:hover, .login-dialog-button.login-dialog-session-list-button:hover, .screenshot-ui-show-pointer-button:hover, .message .message-header .message-expand-button:hover,
 +  .message .message-header .message-close-button:hover, .calendar .calendar-month-header .pager-button:hover, .button:hover {
 +    color: #282828;
-     color: rgba(40, 40, 40, 0.4);
-     background-color: #e4e4e4; }
++    background-color: st-darken(st-mix(#282828, whitesmoke, 12%), 4%); }
 +  .icon-button:insensitive, .login-dialog-button.cancel-button:insensitive, .login-dialog-button.switch-user-button:insensitive, .login-dialog-button.login-dialog-session-list-button:insensitive, .screenshot-ui-show-pointer-button:insensitive, .message .message-header .message-expand-button:insensitive,
 +  .message .message-header .message-close-button:insensitive, .calendar .calendar-month-header .pager-button:insensitive, .button:insensitive {
-     background-color: #c5c5c5; }
++    color: st-transparentize(#282828, 0.6);
++    background-color: st-lighten(st-mix(#282828, whitesmoke, 12%), 3%); }
 +  .icon-button:selected, .login-dialog-button.cancel-button:selected, .login-dialog-button.switch-user-button:selected, .login-dialog-button.login-dialog-session-list-button:selected, .screenshot-ui-show-pointer-button:selected, .message .message-header .message-expand-button:selected,
 +  .message .message-header .message-close-button:selected, .calendar .calendar-month-header .pager-button:selected, .button:selected, .icon-button:active, .login-dialog-button.cancel-button:active, .login-dialog-button.switch-user-button:active, .login-dialog-button.login-dialog-session-list-button:active, .screenshot-ui-show-pointer-button:active, .message .message-header .message-expand-button:active,
 +  .message .message-header .message-close-button:active, .calendar .calendar-month-header .pager-button:active, .button:active {
 +    color: #282828;
-       background-color: #bbbbbb; }
++    background-color: st-darken(st-mix(#282828, whitesmoke, 12%), 9%); }
 +    .icon-button:selected:hover, .login-dialog-button.cancel-button:selected:hover, .login-dialog-button.switch-user-button:selected:hover, .login-dialog-button.login-dialog-session-list-button:selected:hover, .screenshot-ui-show-pointer-button:selected:hover, .message .message-header .message-expand-button:selected:hover,
 +    .message .message-header .message-close-button:selected:hover, .calendar .calendar-month-header .pager-button:selected:hover, .button:selected:hover, .icon-button:active:hover, .login-dialog-button.cancel-button:active:hover, .login-dialog-button.switch-user-button:active:hover, .login-dialog-button.login-dialog-session-list-button:active:hover, .screenshot-ui-show-pointer-button:active:hover, .message .message-header .message-expand-button:active:hover,
 +    .message .message-header .message-close-button:active:hover, .calendar .calendar-month-header .pager-button:active:hover, .button:active:hover {
-       background-color: #bdc1c6; }
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 9%), 4%); }
 +    .icon-button:selected:focus, .login-dialog-button.cancel-button:selected:focus, .login-dialog-button.switch-user-button:selected:focus, .login-dialog-button.login-dialog-session-list-button:selected:focus, .screenshot-ui-show-pointer-button:selected:focus, .message .message-header .message-expand-button:selected:focus,
 +    .message .message-header .message-close-button:selected:focus, .calendar .calendar-month-header .pager-button:selected:focus, .button:selected:focus, .icon-button:active:focus, .login-dialog-button.cancel-button:active:focus, .login-dialog-button.switch-user-button:active:focus, .login-dialog-button.login-dialog-session-list-button:active:focus, .screenshot-ui-show-pointer-button:active:focus, .message .message-header .message-expand-button:active:focus,
 +    .message .message-header .message-close-button:active:focus, .calendar .calendar-month-header .pager-button:active:focus, .button:active:focus {
-     background-color: #c8c8c8; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, whitesmoke, 12%), 9%), 5%); }
 +  .icon-button:checked, .login-dialog-button.cancel-button:checked, .login-dialog-button.switch-user-button:checked, .login-dialog-button.login-dialog-session-list-button:checked, .screenshot-ui-show-pointer-button:checked, .message .message-header .message-expand-button:checked,
 +  .message .message-header .message-close-button:checked, .calendar .calendar-month-header .pager-button:checked, .button:checked {
 +    color: #282828;
-       background-color: #bdbdbd; }
++    background-color: st-darken(st-mix(#282828, whitesmoke, 12%), 8%); }
 +    .icon-button:checked:hover, .login-dialog-button.cancel-button:checked:hover, .login-dialog-button.switch-user-button:checked:hover, .login-dialog-button.login-dialog-session-list-button:checked:hover, .screenshot-ui-show-pointer-button:checked:hover, .message .message-header .message-expand-button:checked:hover,
 +    .message .message-header .message-close-button:checked:hover, .calendar .calendar-month-header .pager-button:checked:hover, .button:checked:hover {
-       background-color: #b1b1b1; }
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 8%), 4%); }
 +    .icon-button:checked:active, .login-dialog-button.cancel-button:checked:active, .login-dialog-button.switch-user-button:checked:active, .login-dialog-button.login-dialog-session-list-button:checked:active, .screenshot-ui-show-pointer-button:checked:active, .message .message-header .message-expand-button:checked:active,
 +    .message .message-header .message-close-button:checked:active, .calendar .calendar-month-header .pager-button:checked:active, .button:checked:active {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(187, 209, 237, 0.2875); }
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 8%), 9%); }
 +
 +.calendar .calendar-day-heading, .calendar .calendar-day, .calendar .calendar-month-header .calendar-month-label, .icon-button.flat, .flat.login-dialog-button.cancel-button, .flat.login-dialog-button.switch-user-button, .flat.login-dialog-button.login-dialog-session-list-button, .flat.screenshot-ui-show-pointer-button, .message .message-header .flat.message-expand-button,
 +.message .message-header .flat.message-close-button, .calendar .calendar-month-header .pager-button, .button.flat {
 +  color: #282828;
 +  background-color: whitesmoke; }
 +  .calendar .calendar-day-heading:focus, .calendar .calendar-day:focus, .calendar .calendar-month-header .calendar-month-label:focus, .icon-button.flat:focus, .flat.login-dialog-button.cancel-button:focus, .flat.login-dialog-button.switch-user-button:focus, .flat.login-dialog-button.login-dialog-session-list-button:focus, .flat.screenshot-ui-show-pointer-button:focus, .message .message-header .flat.message-expand-button:focus,
 +  .message .message-header .flat.message-close-button:focus, .calendar .calendar-month-header .pager-button:focus, .button.flat:focus {
 +    color: #282828;
-       background-color: #d9dde3; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.25), 5%); }
 +    .calendar .calendar-day-heading:focus:hover, .calendar .calendar-day:focus:hover, .calendar .calendar-month-header .calendar-month-label:focus:hover, .icon-button.flat:focus:hover, .flat.login-dialog-button.cancel-button:focus:hover, .flat.login-dialog-button.switch-user-button:focus:hover, .flat.login-dialog-button.login-dialog-session-list-button:focus:hover, .flat.screenshot-ui-show-pointer-button:focus:hover, .message .message-header .flat.message-expand-button:focus:hover,
 +    .message .message-header .flat.message-close-button:focus:hover, .calendar .calendar-month-header .pager-button:focus:hover, .button.flat:focus:hover {
-     background-color: #e3e3e3; }
++      background-color: st-mix(-st-accent-color, st-darken(whitesmoke, 7%), 5%); }
 +  .calendar .calendar-day-heading:hover, .calendar .calendar-day:hover, .calendar .calendar-month-header .calendar-month-label:hover, .icon-button.flat:hover, .flat.login-dialog-button.cancel-button:hover, .flat.login-dialog-button.switch-user-button:hover, .flat.login-dialog-button.login-dialog-session-list-button:hover, .flat.screenshot-ui-show-pointer-button:hover, .message .message-header .flat.message-expand-button:hover,
 +  .message .message-header .flat.message-close-button:hover, .calendar .calendar-month-header .pager-button:hover, .button.flat:hover {
 +    color: #282828;
-     color: rgba(40, 40, 40, 0.4);
++    background-color: st-darken(whitesmoke, 7%); }
 +  .calendar .calendar-day-heading:insensitive, .calendar .calendar-day:insensitive, .calendar .calendar-month-header .calendar-month-label:insensitive, .icon-button.flat:insensitive, .flat.login-dialog-button.cancel-button:insensitive, .flat.login-dialog-button.switch-user-button:insensitive, .flat.login-dialog-button.login-dialog-session-list-button:insensitive, .flat.screenshot-ui-show-pointer-button:insensitive, .message .message-header .flat.message-expand-button:insensitive,
 +  .message .message-header .flat.message-close-button:insensitive, .calendar .calendar-month-header .pager-button:insensitive, .button.flat:insensitive {
-     background-color: #dedede; }
++    color: st-transparentize(#282828, 0.6);
 +    background-color: whitesmoke; }
 +  .calendar .calendar-day-heading:selected, .calendar .calendar-day:selected, .calendar .calendar-month-header .calendar-month-label:selected, .icon-button.flat:selected, .flat.login-dialog-button.cancel-button:selected, .flat.login-dialog-button.switch-user-button:selected, .flat.login-dialog-button.login-dialog-session-list-button:selected, .flat.screenshot-ui-show-pointer-button:selected, .message .message-header .flat.message-expand-button:selected,
 +  .message .message-header .flat.message-close-button:selected, .calendar .calendar-month-header .pager-button:selected, .button.flat:selected, .calendar .calendar-day-heading:active, .calendar .calendar-day:active, .calendar .calendar-month-header .calendar-month-label:active, .icon-button.flat:active, .flat.login-dialog-button.cancel-button:active, .flat.login-dialog-button.switch-user-button:active, .flat.login-dialog-button.login-dialog-session-list-button:active, .flat.screenshot-ui-show-pointer-button:active, .message .message-header .flat.message-expand-button:active,
 +  .message .message-header .flat.message-close-button:active, .calendar .calendar-month-header .pager-button:active, .button.flat:active {
 +    color: #282828;
-       background-color: #cccccc; }
++    background-color: st-darken(whitesmoke, 9%); }
 +    .calendar .calendar-day-heading:selected:hover, .calendar .calendar-day:selected:hover, .calendar .calendar-month-header .calendar-month-label:selected:hover, .icon-button.flat:selected:hover, .flat.login-dialog-button.cancel-button:selected:hover, .flat.login-dialog-button.switch-user-button:selected:hover, .flat.login-dialog-button.login-dialog-session-list-button:selected:hover, .flat.screenshot-ui-show-pointer-button:selected:hover, .message .message-header .flat.message-expand-button:selected:hover,
 +    .message .message-header .flat.message-close-button:selected:hover, .calendar .calendar-month-header .pager-button:selected:hover, .button.flat:selected:hover, .calendar .calendar-day-heading:active:hover, .calendar .calendar-day:active:hover, .calendar .calendar-month-header .calendar-month-label:active:hover, .icon-button.flat:active:hover, .flat.login-dialog-button.cancel-button:active:hover, .flat.login-dialog-button.switch-user-button:active:hover, .flat.login-dialog-button.login-dialog-session-list-button:active:hover, .flat.screenshot-ui-show-pointer-button:active:hover, .message .message-header .flat.message-expand-button:active:hover,
 +    .message .message-header .flat.message-close-button:active:hover, .calendar .calendar-month-header .pager-button:active:hover, .button.flat:active:hover {
-       background-color: #d4d9de; }
++      background-color: st-darken(st-darken(whitesmoke, 9%), 7%); }
 +    .calendar .calendar-day-heading:selected:focus, .calendar .calendar-day:selected:focus, .calendar .calendar-month-header .calendar-month-label:selected:focus, .icon-button.flat:selected:focus, .flat.login-dialog-button.cancel-button:selected:focus, .flat.login-dialog-button.switch-user-button:selected:focus, .flat.login-dialog-button.login-dialog-session-list-button:selected:focus, .flat.screenshot-ui-show-pointer-button:selected:focus, .message .message-header .flat.message-expand-button:selected:focus,
 +    .message .message-header .flat.message-close-button:selected:focus, .calendar .calendar-month-header .pager-button:selected:focus, .button.flat:selected:focus, .calendar .calendar-day-heading:active:focus, .calendar .calendar-day:active:focus, .calendar .calendar-month-header .calendar-month-label:active:focus, .icon-button.flat:active:focus, .flat.login-dialog-button.cancel-button:active:focus, .flat.login-dialog-button.switch-user-button:active:focus, .flat.login-dialog-button.login-dialog-session-list-button:active:focus, .flat.screenshot-ui-show-pointer-button:active:focus, .message .message-header .flat.message-expand-button:active:focus,
 +    .message .message-header .flat.message-close-button:active:focus, .calendar .calendar-month-header .pager-button:active:focus, .button.flat:active:focus {
-     background-color: #e1e1e1; }
++      background-color: st-mix(-st-accent-color, st-darken(whitesmoke, 9%), 5%); }
 +  .calendar .calendar-day-heading:checked, .calendar .calendar-day:checked, .calendar .calendar-month-header .calendar-month-label:checked, .icon-button.flat:checked, .flat.login-dialog-button.cancel-button:checked, .flat.login-dialog-button.switch-user-button:checked, .flat.login-dialog-button.login-dialog-session-list-button:checked, .flat.screenshot-ui-show-pointer-button:checked, .message .message-header .flat.message-expand-button:checked,
 +  .message .message-header .flat.message-close-button:checked, .calendar .calendar-month-header .pager-button:checked, .button.flat:checked {
 +    color: #282828;
-       background-color: #cfcfcf; }
++    background-color: st-darken(whitesmoke, 8%); }
 +    .calendar .calendar-day-heading:checked:hover, .calendar .calendar-day:checked:hover, .calendar .calendar-month-header .calendar-month-label:checked:hover, .icon-button.flat:checked:hover, .flat.login-dialog-button.cancel-button:checked:hover, .flat.login-dialog-button.switch-user-button:checked:hover, .flat.login-dialog-button.login-dialog-session-list-button:checked:hover, .flat.screenshot-ui-show-pointer-button:checked:hover, .message .message-header .flat.message-expand-button:checked:hover,
 +    .message .message-header .flat.message-close-button:checked:hover, .calendar .calendar-month-header .pager-button:checked:hover, .button.flat:checked:hover {
-       background-color: #cacaca; }
++      background-color: st-darken(st-darken(whitesmoke, 8%), 7%); }
 +    .calendar .calendar-day-heading:checked:active, .calendar .calendar-day:checked:active, .calendar .calendar-month-header .calendar-month-label:checked:active, .icon-button.flat:checked:active, .flat.login-dialog-button.cancel-button:checked:active, .flat.login-dialog-button.switch-user-button:checked:active, .flat.login-dialog-button.login-dialog-session-list-button:checked:active, .flat.screenshot-ui-show-pointer-button:checked:active, .message .message-header .flat.message-expand-button:checked:active,
 +    .message .message-header .flat.message-close-button:checked:active, .calendar .calendar-month-header .pager-button:checked:active, .button.flat:checked:active {
-   color: #ffffff;
-   background-color: #1c71d8; }
++      background-color: st-darken(st-darken(whitesmoke, 8%), 9%); }
 +
 +.keyboard-brightness-level .button:checked, .quick-menu-toggle .quick-toggle-arrow:checked, .quick-toggle:checked, .calendar .calendar-day.calendar-today, .icon-button.default, .default.login-dialog-button.cancel-button, .default.login-dialog-button.switch-user-button, .default.login-dialog-button.login-dialog-session-list-button, .default.screenshot-ui-show-pointer-button, .message .message-header .default.message-expand-button,
 +.message .message-header .default.message-close-button, .calendar .calendar-month-header .default.pager-button, .button.default {
-     color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     box-shadow: inset 0 0 0 2px #134e94 !important;
-     background-color: #1c71d8; }
++  color: -st-accent-fg-color;
++  background-color: -st-accent-color; }
 +  .keyboard-brightness-level .button:focus:checked, .quick-menu-toggle .quick-toggle-arrow:focus:checked, .quick-toggle:focus:checked, .calendar .calendar-day.calendar-today:focus, .icon-button.default:focus, .default.login-dialog-button.cancel-button:focus, .default.login-dialog-button.switch-user-button:focus, .default.login-dialog-button.login-dialog-session-list-button:focus, .default.screenshot-ui-show-pointer-button:focus, .message .message-header .default.message-expand-button:focus,
 +  .message .message-header .default.message-close-button:focus, .calendar .calendar-month-header .default.pager-button:focus, .button.default:focus {
-       background-color: #1a68c7; }
++    color: -st-accent-fg-color;
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    box-shadow: inset 0 0 0 2px st-darken(-st-accent-color, 15%) !important;
++    background-color: st-mix(-st-accent-color, -st-accent-color, 5%); }
 +    .keyboard-brightness-level .button:focus:hover:checked, .quick-menu-toggle .quick-toggle-arrow:focus:hover:checked, .quick-toggle:focus:hover:checked, .calendar .calendar-day.calendar-today:focus:hover, .icon-button.default:focus:hover, .default.login-dialog-button.cancel-button:focus:hover, .default.login-dialog-button.switch-user-button:focus:hover, .default.login-dialog-button.login-dialog-session-list-button:focus:hover, .default.screenshot-ui-show-pointer-button:focus:hover, .message .message-header .default.message-expand-button:focus:hover,
 +    .message .message-header .default.message-close-button:focus:hover, .calendar .calendar-month-header .default.pager-button:focus:hover, .button.default:focus:hover {
-     color: #ffffff;
-     background-color: #1a68c6; }
++      background-color: st-mix(-st-accent-color, st-darken(-st-accent-color, 4%), 5%); }
 +  .keyboard-brightness-level .button:hover:checked, .quick-menu-toggle .quick-toggle-arrow:hover:checked, .quick-toggle:hover:checked, .calendar .calendar-day.calendar-today:hover, .icon-button.default:hover, .default.login-dialog-button.cancel-button:hover, .default.login-dialog-button.switch-user-button:hover, .default.login-dialog-button.login-dialog-session-list-button:hover, .default.screenshot-ui-show-pointer-button:hover, .message .message-header .default.message-expand-button:hover,
 +  .message .message-header .default.message-close-button:hover, .calendar .calendar-month-header .default.pager-button:hover, .button.default:hover {
-     color: rgba(255, 255, 255, 0.4);
-     background-color: #2178e2; }
++    color: -st-accent-fg-color;
++    background-color: st-darken(-st-accent-color, 4%); }
 +  .keyboard-brightness-level .button:insensitive:checked, .quick-menu-toggle .quick-toggle-arrow:insensitive:checked, .quick-toggle:insensitive:checked, .calendar .calendar-day.calendar-today:insensitive, .icon-button.default:insensitive, .default.login-dialog-button.cancel-button:insensitive, .default.login-dialog-button.switch-user-button:insensitive, .default.login-dialog-button.login-dialog-session-list-button:insensitive, .default.screenshot-ui-show-pointer-button:insensitive, .message .message-header .default.message-expand-button:insensitive,
 +  .message .message-header .default.message-close-button:insensitive, .calendar .calendar-month-header .default.pager-button:insensitive, .button.default:insensitive {
-     color: #ffffff;
-     background-color: #175caf; }
++    color: st-transparentize(-st-accent-fg-color, 0.6);
++    background-color: st-lighten(-st-accent-color, 3%); }
 +  .keyboard-brightness-level .button:active:checked, .quick-menu-toggle .quick-toggle-arrow:active:checked, .quick-toggle:active:checked, .calendar .calendar-day.calendar-today:active, .icon-button.default:active, .default.login-dialog-button.cancel-button:active, .default.login-dialog-button.switch-user-button:active, .default.login-dialog-button.login-dialog-session-list-button:active, .default.screenshot-ui-show-pointer-button:active, .message .message-header .default.message-expand-button:active,
 +  .message .message-header .default.message-close-button:active, .calendar .calendar-month-header .default.pager-button:active, .button.default:active {
-       background-color: #14529d; }
++    color: -st-accent-fg-color;
++    background-color: st-darken(-st-accent-color, 9%); }
 +    .keyboard-brightness-level .button:active:hover:checked, .quick-menu-toggle .quick-toggle-arrow:active:hover:checked, .quick-toggle:active:hover:checked, .calendar .calendar-day.calendar-today:active:hover, .icon-button.default:active:hover, .default.login-dialog-button.cancel-button:active:hover, .default.login-dialog-button.switch-user-button:active:hover, .default.login-dialog-button.login-dialog-session-list-button:active:hover, .default.screenshot-ui-show-pointer-button:active:hover, .message .message-header .default.message-expand-button:active:hover,
 +    .message .message-header .default.message-close-button:active:hover, .calendar .calendar-month-header .default.pager-button:active:hover, .button.default:active:hover {
-       background-color: #175db1; }
++      background-color: st-darken(st-darken(-st-accent-color, 9%), 4%); }
 +    .keyboard-brightness-level .button:active:focus:checked, .quick-menu-toggle .quick-toggle-arrow:active:focus:checked, .quick-toggle:active:focus:checked, .calendar .calendar-day.calendar-today:active:focus, .icon-button.default:active:focus, .default.login-dialog-button.cancel-button:active:focus, .default.login-dialog-button.switch-user-button:active:focus, .default.login-dialog-button.login-dialog-session-list-button:active:focus, .default.screenshot-ui-show-pointer-button:active:focus, .message .message-header .default.message-expand-button:active:focus,
 +    .message .message-header .default.message-close-button:active:focus, .calendar .calendar-month-header .default.pager-button:active:focus, .button.default:active:focus {
- .calendar, .datemenu-today-button, .lg-extension, .quick-toggle-menu, .message, .events-button,
++      background-color: st-mix(-st-accent-color, st-darken(-st-accent-color, 9%), 5%); }
 +
 +.popup-sub-menu .popup-menu-item, .popup-menu-item {
 +  font-weight: normal;
 +  spacing: 6px;
 +  transition-duration: 100ms;
 +  padding: 9px 12px; }
 +
- .lg-extension, .quick-toggle-menu, .message, .events-button,
++#LookingGlassExtensions .lg-extension, #LookingGlassWindows .lg-window, .calendar, .datemenu-today-button, .quick-toggle-menu, .message, .events-button,
 +.world-clocks-button,
 +.weather-button {
 +  border-radius: 12px;
 +  padding: 0.818em;
 +  margin: 4px;
 +  background-color: #ffffff;
 +  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
 +  border: 1px solid rgba(0, 0, 0, 0.09); }
 +
-   .lg-extension:hover, .quick-toggle-menu:hover, .message:hover, .events-button:hover,
++.quick-toggle-menu, .message, .events-button,
 +.world-clocks-button,
 +.weather-button {
 +  color: #282828;
 +  background-color: #ffffff; }
-     background-color: whitesmoke; }
-   .lg-extension:active, .quick-toggle-menu:active, .message:active, .events-button:active,
++  .quick-toggle-menu:hover, .message:hover, .events-button:hover,
 +  .world-clocks-button:hover,
 +  .weather-button:hover {
 +    color: #282828;
-     background-color: #e8e8e8; }
-     .lg-extension:active:hover, .quick-toggle-menu:active:hover, .message:active:hover, .events-button:active:hover,
++    background-color: st-darken(#ffffff, 4%); }
++  .quick-toggle-menu:active, .message:active, .events-button:active,
 +  .world-clocks-button:active,
 +  .weather-button:active {
 +    color: #282828;
-       background-color: #dedede; }
-     .lg-extension:active:focus, .quick-toggle-menu:active:focus, .message:active:focus, .events-button:active:focus,
++    background-color: st-darken(#ffffff, 9%); }
++    .quick-toggle-menu:active:hover, .message:active:hover, .events-button:active:hover,
 +    .world-clocks-button:active:hover,
 +    .weather-button:active:hover {
-       background-color: #dee2e7; }
-   .lg-extension:focus, .quick-toggle-menu:focus, .message:focus, .events-button:focus,
++      background-color: st-darken(st-darken(#ffffff, 9%), 4%); }
++    .quick-toggle-menu:active:focus, .message:active:focus, .events-button:active:focus,
 +    .world-clocks-button:active:focus,
 +    .weather-button:active:focus {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #f4f8fd; }
-     .lg-extension:focus:hover, .quick-toggle-menu:focus:hover, .message:focus:hover, .events-button:focus:hover,
++      background-color: st-mix(-st-accent-color, st-darken(#ffffff, 9%), 5%); }
++  .quick-toggle-menu:focus, .message:focus, .events-button:focus,
 +  .world-clocks-button:focus,
 +  .weather-button:focus {
 +    color: #282828;
-       background-color: #eaeef3; }
-   .lg-extension:insensitive, .quick-toggle-menu:insensitive, .message:insensitive, .events-button:insensitive,
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #ffffff, 5%); }
++    .quick-toggle-menu:focus:hover, .message:focus:hover, .events-button:focus:hover,
 +    .world-clocks-button:focus:hover,
 +    .weather-button:focus:hover {
-     color: rgba(40, 40, 40, 0.4);
-     background-color: white; }
++      background-color: st-mix(-st-accent-color, st-darken(#ffffff, 4%), 5%); }
++  .quick-toggle-menu:insensitive, .message:insensitive, .events-button:insensitive,
 +  .world-clocks-button:insensitive,
 +  .weather-button:insensitive {
-     background-color: #e3e3e3; }
++    color: st-transparentize(#282828, 0.6);
++    background-color: st-lighten(#ffffff, 3%); }
 +
 +.calendar, .datemenu-today-button {
 +  border: 1px solid transparent !important;
 +  background-color: transparent;
 +  border-color: transparent;
 +  box-shadow: none; }
 +  .calendar:insensitive, .datemenu-today-button:insensitive {
 +    background-color: transparent !important; }
 +  .calendar:hover, .datemenu-today-button:hover {
 +    color: #282828;
-     background-color: #dedede; }
++    background-color: st-darken(whitesmoke, 7%); }
 +  .calendar:active, .datemenu-today-button:active {
 +    color: #282828;
-       background-color: #cccccc; }
++    background-color: st-darken(whitesmoke, 9%); }
 +    .calendar:active:hover, .datemenu-today-button:active:hover {
-       background-color: #d4d9de; }
++      background-color: st-darken(st-darken(whitesmoke, 9%), 7%); }
 +    .calendar:active:focus, .datemenu-today-button:active:focus {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #f4f8fd; }
++      background-color: st-mix(-st-accent-color, st-darken(whitesmoke, 9%), 5%); }
 +  .calendar:focus, .datemenu-today-button:focus {
 +    color: #282828;
-       background-color: #eaeef3; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #ffffff, 5%); }
 +    .calendar:focus:hover, .datemenu-today-button:focus:hover {
-     color: rgba(40, 40, 40, 0.4);
-     background-color: white; }
++      background-color: st-mix(-st-accent-color, st-darken(#ffffff, 4%), 5%); }
 +  .calendar:insensitive, .datemenu-today-button:insensitive {
-   selection-background-color: #1c71d8;
-   selected-color: #ffffff; }
++    color: st-transparentize(#282828, 0.6);
++    background-color: st-lighten(#ffffff, 3%); }
 +
 +.unlock-dialog .login-dialog-prompt-entry, .login-dialog .login-dialog-prompt-entry, .app-folder-dialog .folder-name-container .folder-name-entry, .search-entry, .lg-dialog StEntry, StEntry {
 +  border-radius: 8px;
 +  padding: 9px 9px;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #d2d7dc;
++  selection-background-color: st-transparentize(-st-accent-color, 0.7);
++  selected-color: #282828; }
 +
 +StEntry {
 +  background-color: gainsboro;
 +  color: rgba(40, 40, 40, 0.7); }
 +  StEntry:hover {
 +    background-color: #d2d2d2;
 +    color: #282828; }
 +  StEntry:focus {
- .modal-dialog .modal-dialog-linked-button, .notification-button {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, gainsboro, 5%);
 +    color: #282828; }
 +  StEntry:insensitive {
 +    background-color: #e4e4e4;
 +    color: rgba(40, 40, 40, 0.5); }
 +  StEntry StLabel.hint-text {
 +    color: rgba(40, 40, 40, 0.7); }
 +
-   font-weight: bold !important;
++.notification-button, .message .message-header .message-expand-button,
++.message .message-header .message-close-button {
++  font-weight: bold;
++  padding: 6px 12px;
++  border-radius: 8px;
++  color: #282828;
++  background-color: rgba(40, 40, 40, 0.15); }
++  .notification-button:focus, .message .message-header .message-expand-button:focus,
++  .message .message-header .message-close-button:focus {
++    color: #282828;
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.15), 5%); }
++    .notification-button:focus:hover, .message .message-header .message-expand-button:focus:hover,
++    .message .message-header .message-close-button:focus:hover {
++      background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.3), 5%); }
++  .notification-button:hover, .message .message-header .message-expand-button:hover,
++  .message .message-header .message-close-button:hover {
++    color: #282828;
++    background-color: rgba(40, 40, 40, 0.3); }
++  .notification-button:active, .message .message-header .message-expand-button:active,
++  .message .message-header .message-close-button:active {
++    color: #282828;
++    background-color: rgba(40, 40, 40, 0.2); }
++    .notification-button:active:hover, .message .message-header .message-expand-button:active:hover,
++    .message .message-header .message-close-button:active:hover {
++      background-color: rgba(40, 40, 40, 0.2); }
++    .notification-button:active:focus, .message .message-header .message-expand-button:active:focus,
++    .message .message-header .message-close-button:active:focus {
++      background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.2), 5%); }
++  .notification-button:checked, .message .message-header .message-expand-button:checked,
++  .message .message-header .message-close-button:checked {
++    color: #282828;
++    background-color: st-darken(st-mix(#282828, whitesmoke, 12%), 8%); }
++    .notification-button:checked:hover, .message .message-header .message-expand-button:checked:hover,
++    .message .message-header .message-close-button:checked:hover {
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 8%), 4%); }
++    .notification-button:checked:active, .message .message-header .message-expand-button:checked:active,
++    .message .message-header .message-close-button:checked:active {
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 8%), 9%); }
++  .notification-button:insensitive, .message .message-header .message-expand-button:insensitive,
++  .message .message-header .message-close-button:insensitive {
++    color: st-transparentize(#282828, 0.6);
++    background-color: rgba(40, 40, 40, 0.1); }
++
++.modal-dialog .modal-dialog-linked-button {
++  font-weight: bold;
 +  padding: 12px;
-   .modal-dialog .modal-dialog-linked-button:ltr, .notification-button:ltr {
-     margin-right: 1px; }
-   .modal-dialog .modal-dialog-linked-button:rtl, .notification-button:rtl {
-     margin-left: 1px; }
-   .modal-dialog .modal-dialog-linked-button:focus, .notification-button:focus {
++  border-radius: 12px;
 +  color: #282828;
 +  background-color: rgba(40, 40, 40, 0.1); }
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(34, 77, 128, 0.145); }
-     .modal-dialog .modal-dialog-linked-button:focus:hover, .notification-button:focus:hover {
-       background-color: rgba(35, 71, 116, 0.1735); }
-   .modal-dialog .modal-dialog-linked-button:hover, .notification-button:hover {
++  .modal-dialog .modal-dialog-linked-button:focus {
 +    color: #282828;
-   .modal-dialog .modal-dialog-linked-button:active, .notification-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.1), 5%); }
++    .modal-dialog .modal-dialog-linked-button:focus:hover {
++      background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.13), 5%); }
++  .modal-dialog .modal-dialog-linked-button:hover {
 +    color: #282828;
 +    background-color: rgba(40, 40, 40, 0.13); }
-     .modal-dialog .modal-dialog-linked-button:active:hover, .notification-button:active:hover {
++  .modal-dialog .modal-dialog-linked-button:active {
 +    color: #282828;
 +    background-color: rgba(40, 40, 40, 0.16); }
-     .modal-dialog .modal-dialog-linked-button:active:focus, .notification-button:active:focus {
-       background-color: rgba(35, 68, 106, 0.202); }
-   .modal-dialog .modal-dialog-linked-button:checked, .notification-button:checked {
++    .modal-dialog .modal-dialog-linked-button:active:hover {
 +      background-color: rgba(40, 40, 40, 0.19); }
-     background-color: #c8c8c8; }
-     .modal-dialog .modal-dialog-linked-button:checked:hover, .notification-button:checked:hover {
-       background-color: #bdbdbd; }
-     .modal-dialog .modal-dialog-linked-button:checked:active, .notification-button:checked:active {
-       background-color: #b1b1b1; }
-   .modal-dialog .modal-dialog-linked-button:insensitive, .notification-button:insensitive {
-     color: rgba(40, 40, 40, 0.4);
-     background-color: #e4e4e4; }
-   .modal-dialog .modal-dialog-linked-button:first-child:ltr, .notification-button:first-child:ltr {
-     border-radius: 0 0 0 15px; }
-   .modal-dialog .modal-dialog-linked-button:last-child:ltr, .notification-button:last-child:ltr {
-     border-radius: 0 0 15px;
-     margin-right: 0 !important; }
-   .modal-dialog .modal-dialog-linked-button:first-child:rtl, .notification-button:first-child:rtl {
-     border-radius: 0 0 15px; }
-   .modal-dialog .modal-dialog-linked-button:last-child:rtl, .notification-button:last-child:rtl {
-     border-radius: 0 0 0 15px;
-     margin-left: 0 !important; }
-   .modal-dialog .modal-dialog-linked-button:first-child:last-child, .notification-button:first-child:last-child {
-     border-radius: 0 0 15px 15px;
-     margin-left: 0 !important;
-     margin-right: 0 !important; }
++    .modal-dialog .modal-dialog-linked-button:active:focus {
++      background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.16), 5%); }
++  .modal-dialog .modal-dialog-linked-button:checked {
 +    color: #282828;
- .login-dialog .user-widget.vertical .user-widget-label,
- .unlock-dialog .user-widget.vertical .user-widget-label, .unlock-dialog-clock .unlock-dialog-clock-date, .app-folder-dialog .folder-name-container .folder-name-label, .app-folder-dialog .folder-name-container .folder-name-entry, .search-statustext {
++    background-color: st-darken(st-mix(#282828, whitesmoke, 12%), 8%); }
++    .modal-dialog .modal-dialog-linked-button:checked:hover {
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 8%), 4%); }
++    .modal-dialog .modal-dialog-linked-button:checked:active {
++      background-color: st-darken(st-darken(st-mix(#282828, whitesmoke, 12%), 8%), 9%); }
++  .modal-dialog .modal-dialog-linked-button:insensitive {
++    color: st-transparentize(#282828, 0.6);
++    background-color: st-lighten(st-mix(#282828, whitesmoke, 12%), 3%); }
 +
 +.dash-label, .window-caption, .screenshot-ui-tooltip {
 +  background-color: rgba(0, 0, 0, 0.9);
 +  border: 1px solid rgba(255, 255, 255, 0.1);
 +  color: #ffffff;
 +  border-radius: 999px;
 +  padding: 6px 12px;
 +  text-align: center; }
 +
 +/* General Typography */
- .conflicting-session-dialog-content .conflicting-session-dialog-title, .lg-debug-flags-header, .message-dialog-content .message-dialog-title, .message-list .message-list-placeholder, .datemenu-today-button .date-label {
++.unlock-dialog-clock .unlock-dialog-clock-date, .app-folder-dialog .folder-name-container .folder-name-label, .app-folder-dialog .folder-name-container .folder-name-entry, .search-statustext {
 +  font-weight: 800;
 +  font-size: 1.818em; }
 +
- .login-dialog-auth-list-label, .word-suggestions, .bt-menu-placeholder.popup-menu-item, .message-dialog-content .message-dialog-title.lightweight, .headline {
++.conflicting-session-dialog-content .conflicting-session-dialog-title, .message-dialog-content .message-dialog-title, .message-list .message-list-placeholder, .datemenu-today-button .date-label {
 +  font-weight: 800;
 +  font-size: 1.364em; }
 +
 +.login-dialog .user-widget.horizontal .user-widget-label,
 +.unlock-dialog .user-widget.horizontal .user-widget-label, .quick-toggle-menu .header .title {
 +  font-weight: 700;
 +  font-size: 1.364em; }
 +
- .login-dialog-not-listed-label, .lg-extension-name, .background-app-item .title, .osd-window, .dialog-list .dialog-list-title, .message-list-controls, .weather-button .weather-box .weather-header-box .weather-header, .world-clocks-button .world-clocks-header, .events-button .events-box .events-list .event-box .event-summary, .events-button .events-box .events-title, .calendar .calendar-month-header .calendar-month-label {
++.login-dialog-auth-list-label, #LookingGlassDebugFlags .lg-debug-flags-header, #LookingGlassExtensions .lg-extensions-none, .word-suggestions, .bt-menu-placeholder.popup-menu-item, .message-dialog-content .message-dialog-title.lightweight, .headline {
 +  font-weight: 700;
 +  font-size: 1.182em; }
 +
- #EvalBox {
++.login-dialog-not-listed-label, #LookingGlassExtensions .lg-extension .lg-extension-name, #LookingGlassWindows .lg-window .lg-window-name, #LookingGlassPropertyInspector .lg-obj-inspector-title, .background-app-item .title, .osd-window, .dialog-list .dialog-list-title, .message-list-controls, .weather-button .weather-box .weather-header-box .weather-header, .world-clocks-button .world-clocks-header, .events-button .events-box .events-list .event-box .event-summary, .events-button .events-box .events-title, .calendar .calendar-month-header .calendar-month-label {
 +  font-weight: 700;
 +  font-size: 1em; }
 +
 +.quick-toggle-menu .header .subtitle, .app-menu .popup-inactive-menu-item:first-child > StLabel {
 +  font-weight: 700;
 +  font-size: 0.818em; }
 +
 +.lg-completions-text, .caps-lock-warning-label, .background-app-item .subtitle, .quick-toggle StBoxLayout > .quick-toggle-subtitle, .screenshot-ui-type-button .icon-label-button-container, .prompt-dialog-error-label,
 +.prompt-dialog-info-label,
 +.prompt-dialog-null-label, .run-dialog .run-dialog-description, .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-description, .message .message-header .message-header-content .event-time, .world-clocks-button .world-clocks-grid .world-clocks-timezone, .events-button .events-box .events-list .event-box .event-time {
 +  font-weight: 400;
 +  font-size: 0.818em; }
 +
 +.weather-button .weather-box .weather-grid .weather-forecast-time, .calendar .calendar-week-number, .calendar .calendar-day-heading, .calendar .calendar-day {
 +  font-weight: 400;
 +  font-size: 0.818em; }
 +
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #4b4f54;
++#LookingGlassDebugFlags .lg-debug-flag-button StLabel, #LookingGlassEvaluator .evaluator-results, .lg-dialog .actor-link {
 +  font-family: monospace; }
 +
 +.unlock-dialog-clock .unlock-dialog-clock-time, #panel, .weather-button .weather-box .weather-grid .weather-forecast-temp, .world-clocks-button .world-clocks-grid .world-clocks-timezone, .world-clocks-button .world-clocks-grid .world-clocks-time, .events-button .events-box .events-list .event-box .event-time, .calendar .calendar-day-heading, .calendar .calendar-day {
 +  font-feature-settings: "tnum"; }
 +
 +/* OSD Elements */
 +#LookingGlassDialog, .screenshot-ui-panel, .workspace-switcher, .switcher-list, .resize-popup, .osd-window {
 +  color: #ffffff;
 +  background-color: #353535;
 +  border: 1px solid rgba(255, 255, 255, 0.02);
 +  border-radius: 999px;
 +  padding: 12px; }
 +
 +.lg-dialog StEntry {
 +  background-color: #4d4d4d;
 +  color: rgba(255, 255, 255, 0.7); }
 +  .lg-dialog StEntry:hover {
 +    background-color: #575757;
 +    color: #ffffff; }
 +  .lg-dialog StEntry:focus {
- #LookingGlassDialog .notebook-tab, #LookingGlassDialog > #Toolbar .lg-toolbar-button {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #4d4d4d, 5%);
 +    color: #ffffff; }
 +  .lg-dialog StEntry:insensitive {
 +    background-color: #454545;
 +    color: rgba(255, 255, 255, 0.5); }
 +  .lg-dialog StEntry StLabel.hint-text {
 +    color: rgba(255, 255, 255, 0.7); }
 +
-   background-color: #4d4d4d; }
-   #LookingGlassDialog .notebook-tab:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus {
++#LookingGlassDebugFlags .lg-debug-flag-button, #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++#LookingGlassPropertyInspector .lg-obj-inspector-button, #LookingGlassDialog > #Toolbar .lg-toolbar-button {
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #4b4f54; }
-     #LookingGlassDialog .notebook-tab:focus:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus:hover {
-       background-color: #54585e; }
-   #LookingGlassDialog .notebook-tab:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:hover {
++  background-color: st-mix(#ffffff, #353535, 12%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:focus, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:focus,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus {
 +    color: #ffffff;
-     background-color: #575757; }
-   #LookingGlassDialog .notebook-tab:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#ffffff, #353535, 12%), 5%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:focus:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:focus:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:focus:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 12%), 4%), 5%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:hover,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:hover {
 +    color: #ffffff;
-     background-color: #646464; }
-     #LookingGlassDialog .notebook-tab:active:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:hover {
-       background-color: #6e6e6e; }
-     #LookingGlassDialog .notebook-tab:active:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:focus {
-       background-color: #60656a; }
-   #LookingGlassDialog .notebook-tab:checked, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 12%), 4%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:active, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active {
 +    color: #ffffff;
-     background-color: #616161; }
-     #LookingGlassDialog .notebook-tab:checked:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:hover {
-       background-color: #6c6c6c; }
-     #LookingGlassDialog .notebook-tab:checked:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:active {
-       background-color: #787878; }
-   #LookingGlassDialog .notebook-tab:insensitive, #LookingGlassDialog > #Toolbar .lg-toolbar-button:insensitive {
-     color: rgba(255, 255, 255, 0.4);
-     background-color: #454545; }
- 
- .screenshot-ui-show-pointer-button, .screenshot-ui-type-button {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 12%), 9%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:active:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:active:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 12%), 9%), 4%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:active:focus, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:active:focus,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:active:focus, #LookingGlassDialog > #Toolbar .lg-toolbar-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 12%), 9%), 5%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:checked, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:checked, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked {
 +    color: #ffffff;
-   .screenshot-ui-show-pointer-button:focus, .screenshot-ui-type-button:focus {
++    background-color: st-lighten(st-mix(#ffffff, #353535, 12%), 8%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:checked:hover, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked:hover,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:checked:hover, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:hover {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 12%), 8%), 4%); }
++    #LookingGlassDebugFlags .lg-debug-flag-button:checked:active, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:checked:active,
++    #LookingGlassPropertyInspector .lg-obj-inspector-button:checked:active, #LookingGlassDialog > #Toolbar .lg-toolbar-button:checked:active {
++      background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 12%), 8%), 9%); }
++  #LookingGlassDebugFlags .lg-debug-flag-button:insensitive, #LookingGlassPropertyInspector .lg-obj-inspector-close-button:insensitive,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button:insensitive, #LookingGlassDialog > #Toolbar .lg-toolbar-button:insensitive {
++    color: st-transparentize(#ffffff, 0.6);
++    background-color: st-darken(st-mix(#ffffff, #353535, 12%), 3%); }
++
++#LookingGlassDialog .notebook-tab, .screenshot-ui-show-pointer-button, .screenshot-ui-type-button {
 +  color: #ffffff;
 +  background-color: #353535; }
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(46, 69, 97, 0.2875); }
-     .screenshot-ui-show-pointer-button:focus:hover, .screenshot-ui-type-button:focus:hover {
-       background-color: #44494e; }
-   .screenshot-ui-show-pointer-button:hover, .screenshot-ui-type-button:hover {
++  #LookingGlassDialog .notebook-tab:focus, .screenshot-ui-show-pointer-button:focus, .screenshot-ui-type-button:focus {
 +    color: #ffffff;
-     background-color: #474747; }
-   .screenshot-ui-show-pointer-button:active, .screenshot-ui-type-button:active {
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(53, 53, 53, 0.25), 5%); }
++    #LookingGlassDialog .notebook-tab:focus:hover, .screenshot-ui-show-pointer-button:focus:hover, .screenshot-ui-type-button:focus:hover {
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 7%), 5%); }
++  #LookingGlassDialog .notebook-tab:hover, .screenshot-ui-show-pointer-button:hover, .screenshot-ui-type-button:hover {
 +    color: #ffffff;
-     background-color: #4c4c4c; }
-     .screenshot-ui-show-pointer-button:active:hover, .screenshot-ui-type-button:active:hover {
-       background-color: #5e5e5e; }
-     .screenshot-ui-show-pointer-button:active:focus, .screenshot-ui-type-button:active:focus {
-       background-color: #494e53; }
-   .screenshot-ui-show-pointer-button:checked, .screenshot-ui-type-button:checked {
++    background-color: st-lighten(#353535, 7%); }
++  #LookingGlassDialog .notebook-tab:active, .screenshot-ui-show-pointer-button:active, .screenshot-ui-type-button:active {
 +    color: #ffffff;
-     background-color: #494949; }
-     .screenshot-ui-show-pointer-button:checked:hover, .screenshot-ui-type-button:checked:hover {
-       background-color: #5b5b5b; }
-     .screenshot-ui-show-pointer-button:checked:active, .screenshot-ui-type-button:checked:active {
-       background-color: #606060; }
-   .screenshot-ui-show-pointer-button:insensitive, .screenshot-ui-type-button:insensitive {
-     color: rgba(255, 255, 255, 0.4);
++    background-color: st-lighten(#353535, 9%); }
++    #LookingGlassDialog .notebook-tab:active:hover, .screenshot-ui-show-pointer-button:active:hover, .screenshot-ui-type-button:active:hover {
++      background-color: st-lighten(st-lighten(#353535, 9%), 7%); }
++    #LookingGlassDialog .notebook-tab:active:focus, .screenshot-ui-show-pointer-button:active:focus, .screenshot-ui-type-button:active:focus {
++      background-color: st-mix(-st-accent-color, st-lighten(#353535, 9%), 5%); }
++  #LookingGlassDialog .notebook-tab:checked, .screenshot-ui-show-pointer-button:checked, .screenshot-ui-type-button:checked {
 +    color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #4a4e53;
++    background-color: st-lighten(#353535, 8%); }
++    #LookingGlassDialog .notebook-tab:checked:hover, .screenshot-ui-show-pointer-button:checked:hover, .screenshot-ui-type-button:checked:hover {
++      background-color: st-lighten(st-lighten(#353535, 8%), 7%); }
++    #LookingGlassDialog .notebook-tab:checked:active, .screenshot-ui-show-pointer-button:checked:active, .screenshot-ui-type-button:checked:active {
++      background-color: st-lighten(st-lighten(#353535, 8%), 9%); }
++  #LookingGlassDialog .notebook-tab:insensitive, .screenshot-ui-show-pointer-button:insensitive, .screenshot-ui-type-button:insensitive {
++    color: st-transparentize(#ffffff, 0.6);
 +    background-color: #353535; }
 +
 +/* System Elements */
 +.login-dialog .login-dialog-prompt-entry, .app-folder-dialog .folder-name-container .folder-name-entry, .search-entry {
 +  background-color: #4c4c4c;
 +  color: rgba(245, 245, 245, 0.7); }
 +  .login-dialog .login-dialog-prompt-entry:hover, .app-folder-dialog .folder-name-container .folder-name-entry:hover, .search-entry:hover {
 +    background-color: #565656;
 +    color: whitesmoke; }
 +  .login-dialog .login-dialog-prompt-entry:focus, .app-folder-dialog .folder-name-container .folder-name-entry:focus, .search-entry:focus {
-   background-color: #4c4c4c; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, #4c4c4c, 5%);
 +    color: whitesmoke; }
 +  .login-dialog .login-dialog-prompt-entry:insensitive, .app-folder-dialog .folder-name-container .folder-name-entry:insensitive, .search-entry:insensitive {
 +    background-color: #444444;
 +    color: rgba(245, 245, 245, 0.5); }
 +  .login-dialog .login-dialog-prompt-entry StLabel.hint-text, .app-folder-dialog .folder-name-container .folder-name-entry StLabel.hint-text, .search-entry StLabel.hint-text {
 +    color: rgba(245, 245, 245, 0.7); }
 +
 +.login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button {
 +  color: whitesmoke;
-     color: rgba(245, 245, 245, 0.4);
-     background-color: #545454; }
++  background-color: st-mix(whitesmoke, #353535, 12%); }
 +  .login-dialog-button.cancel-button:insensitive, .login-dialog-button.switch-user-button:insensitive, .login-dialog-button.login-dialog-session-list-button:insensitive {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #4a4e53; }
++    color: st-transparentize(whitesmoke, 0.6);
++    background-color: st-lighten(st-mix(whitesmoke, #353535, 12%), 3%); }
 +  .login-dialog-button.cancel-button:focus, .login-dialog-button.switch-user-button:focus, .login-dialog-button.login-dialog-session-list-button:focus {
 +    color: whitesmoke;
-       background-color: #404449; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(whitesmoke, #353535, 12%), 5%); }
 +    .login-dialog-button.cancel-button:focus:hover, .login-dialog-button.switch-user-button:focus:hover, .login-dialog-button.login-dialog-session-list-button:focus:hover {
-     background-color: #424242; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(whitesmoke, #353535, 12%), 4%), 5%); }
 +  .login-dialog-button.cancel-button:hover, .login-dialog-button.switch-user-button:hover, .login-dialog-button.login-dialog-session-list-button:hover {
 +    color: whitesmoke;
-     background-color: #353535; }
++    background-color: st-darken(st-mix(whitesmoke, #353535, 12%), 4%); }
 +  .login-dialog-button.cancel-button:active, .login-dialog-button.switch-user-button:active, .login-dialog-button.login-dialog-session-list-button:active {
 +    color: whitesmoke;
-       background-color: #2b2b2b; }
++    background-color: st-darken(st-mix(whitesmoke, #353535, 12%), 9%); }
 +    .login-dialog-button.cancel-button:active:hover, .login-dialog-button.switch-user-button:active:hover, .login-dialog-button.login-dialog-session-list-button:active:hover {
-       background-color: #34383d; }
++      background-color: st-darken(st-darken(st-mix(whitesmoke, #353535, 12%), 9%), 4%); }
 +    .login-dialog-button.cancel-button:active:focus, .login-dialog-button.switch-user-button:active:focus, .login-dialog-button.login-dialog-session-list-button:active:focus {
-     background-color: #383838; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(whitesmoke, #353535, 12%), 9%), 5%); }
 +  .login-dialog-button.cancel-button:checked, .login-dialog-button.switch-user-button:checked, .login-dialog-button.login-dialog-session-list-button:checked {
 +    color: whitesmoke;
-       background-color: #2d2d2d; }
++    background-color: st-darken(st-mix(whitesmoke, #353535, 12%), 8%); }
 +    .login-dialog-button.cancel-button:checked:hover, .login-dialog-button.switch-user-button:checked:hover, .login-dialog-button.login-dialog-session-list-button:checked:hover {
-       background-color: #212121; }
++      background-color: st-darken(st-darken(st-mix(whitesmoke, #353535, 12%), 8%), 4%); }
 +    .login-dialog-button.cancel-button:checked:active, .login-dialog-button.switch-user-button:checked:active, .login-dialog-button.login-dialog-session-list-button:checked:active {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(137, 179, 231, 0.145); }
++      background-color: st-darken(st-darken(st-mix(whitesmoke, #353535, 12%), 8%), 9%); }
 +
 +/* Lockscreen Elements */
 +.unlock-dialog .button,
 +.unlock-dialog .icon-button,
 +.unlock-dialog .calendar .calendar-month-header .pager-button,
 +.calendar .calendar-month-header .unlock-dialog .pager-button,
 +.unlock-dialog .message .message-header .message-expand-button,
 +.message .message-header .unlock-dialog .message-expand-button,
 +.unlock-dialog .message .message-header .message-close-button,
 +.message .message-header .unlock-dialog .message-close-button,
 +.unlock-dialog .screenshot-ui-show-pointer-button,
 +.unlock-dialog .login-dialog-button.cancel-button,
 +.unlock-dialog .login-dialog-button.switch-user-button,
 +.unlock-dialog .login-dialog-button.login-dialog-session-list-button {
 +  color: whitesmoke;
 +  background-color: rgba(245, 245, 245, 0.1); }
 +  .unlock-dialog .button:focus,
 +  .unlock-dialog .icon-button:focus,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:focus,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:focus,
 +  .unlock-dialog .message .message-header .message-expand-button:focus,
 +  .message .message-header .unlock-dialog .message-expand-button:focus,
 +  .unlock-dialog .message .message-header .message-close-button:focus,
 +  .message .message-header .unlock-dialog .message-close-button:focus,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:focus,
 +  .unlock-dialog .login-dialog-button.cancel-button:focus,
 +  .unlock-dialog .login-dialog-button.switch-user-button:focus,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:focus {
 +    color: whitesmoke;
-       background-color: rgba(152, 188, 233, 0.1735); }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.1), 5%); }
 +    .unlock-dialog .button:focus:hover,
 +    .unlock-dialog .icon-button:focus:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:focus:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:focus:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:focus:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:focus:hover,
 +    .unlock-dialog .message .message-header .message-close-button:focus:hover,
 +    .message .message-header .unlock-dialog .message-close-button:focus:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:focus:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:focus:hover {
-       background-color: rgba(163, 195, 234, 0.202); }
++      background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.13), 5%); }
 +  .unlock-dialog .button:hover,
 +  .unlock-dialog .icon-button:hover,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:hover,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:hover,
 +  .unlock-dialog .message .message-header .message-expand-button:hover,
 +  .message .message-header .unlock-dialog .message-expand-button:hover,
 +  .unlock-dialog .message .message-header .message-close-button:hover,
 +  .message .message-header .unlock-dialog .message-close-button:hover,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:hover,
 +  .unlock-dialog .login-dialog-button.cancel-button:hover,
 +  .unlock-dialog .login-dialog-button.switch-user-button:hover,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:hover {
 +    color: whitesmoke;
 +    background-color: rgba(245, 245, 245, 0.13); }
 +  .unlock-dialog .button:active,
 +  .unlock-dialog .icon-button:active,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:active,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:active,
 +  .unlock-dialog .message .message-header .message-expand-button:active,
 +  .message .message-header .unlock-dialog .message-expand-button:active,
 +  .unlock-dialog .message .message-header .message-close-button:active,
 +  .message .message-header .unlock-dialog .message-close-button:active,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:active,
 +  .unlock-dialog .login-dialog-button.cancel-button:active,
 +  .unlock-dialog .login-dialog-button.switch-user-button:active,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active {
 +    color: whitesmoke;
 +    background-color: rgba(245, 245, 245, 0.16); }
 +    .unlock-dialog .button:active:hover,
 +    .unlock-dialog .icon-button:active:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:active:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:active:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:active:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:active:hover,
 +    .unlock-dialog .message .message-header .message-close-button:active:hover,
 +    .message .message-header .unlock-dialog .message-close-button:active:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:active:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:active:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:active:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active:hover {
 +      background-color: rgba(245, 245, 245, 0.19); }
 +    .unlock-dialog .button:active:focus,
 +    .unlock-dialog .icon-button:active:focus,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:active:focus,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:active:focus,
 +    .unlock-dialog .message .message-header .message-expand-button:active:focus,
 +    .message .message-header .unlock-dialog .message-expand-button:active:focus,
 +    .unlock-dialog .message .message-header .message-close-button:active:focus,
 +    .message .message-header .unlock-dialog .message-close-button:active:focus,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:active:focus,
 +    .unlock-dialog .login-dialog-button.cancel-button:active:focus,
 +    .unlock-dialog .login-dialog-button.switch-user-button:active:focus,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:active:focus {
-     background-color: #e1e1e1; }
++      background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.16), 5%); }
 +  .unlock-dialog .button:checked,
 +  .unlock-dialog .icon-button:checked,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:checked,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:checked,
 +  .unlock-dialog .message .message-header .message-expand-button:checked,
 +  .message .message-header .unlock-dialog .message-expand-button:checked,
 +  .unlock-dialog .message .message-header .message-close-button:checked,
 +  .message .message-header .unlock-dialog .message-close-button:checked,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:checked,
 +  .unlock-dialog .login-dialog-button.cancel-button:checked,
 +  .unlock-dialog .login-dialog-button.switch-user-button:checked,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked {
 +    color: whitesmoke;
-       background-color: #d6d6d6; }
++    background-color: st-darken(st-mix(whitesmoke, whitesmoke, 12%), 8%); }
 +    .unlock-dialog .button:checked:hover,
 +    .unlock-dialog .icon-button:checked:hover,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:checked:hover,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:checked:hover,
 +    .unlock-dialog .message .message-header .message-expand-button:checked:hover,
 +    .message .message-header .unlock-dialog .message-expand-button:checked:hover,
 +    .unlock-dialog .message .message-header .message-close-button:checked:hover,
 +    .message .message-header .unlock-dialog .message-close-button:checked:hover,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.cancel-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.switch-user-button:checked:hover,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked:hover {
-       background-color: #cacaca; }
++      background-color: st-darken(st-darken(st-mix(whitesmoke, whitesmoke, 12%), 8%), 4%); }
 +    .unlock-dialog .button:checked:active,
 +    .unlock-dialog .icon-button:checked:active,
 +    .unlock-dialog .calendar .calendar-month-header .pager-button:checked:active,
 +    .calendar .calendar-month-header .unlock-dialog .pager-button:checked:active,
 +    .unlock-dialog .message .message-header .message-expand-button:checked:active,
 +    .message .message-header .unlock-dialog .message-expand-button:checked:active,
 +    .unlock-dialog .message .message-header .message-close-button:checked:active,
 +    .message .message-header .unlock-dialog .message-close-button:checked:active,
 +    .unlock-dialog .screenshot-ui-show-pointer-button:checked:active,
 +    .unlock-dialog .login-dialog-button.cancel-button:checked:active,
 +    .unlock-dialog .login-dialog-button.switch-user-button:checked:active,
 +    .unlock-dialog .login-dialog-button.login-dialog-session-list-button:checked:active {
-     color: rgba(245, 245, 245, 0.4);
-     background-color: #fdfdfd; }
++      background-color: st-darken(st-darken(st-mix(whitesmoke, whitesmoke, 12%), 8%), 9%); }
 +  .unlock-dialog .button:insensitive,
 +  .unlock-dialog .icon-button:insensitive,
 +  .unlock-dialog .calendar .calendar-month-header .pager-button:insensitive,
 +  .calendar .calendar-month-header .unlock-dialog .pager-button:insensitive,
 +  .unlock-dialog .message .message-header .message-expand-button:insensitive,
 +  .message .message-header .unlock-dialog .message-expand-button:insensitive,
 +  .unlock-dialog .message .message-header .message-close-button:insensitive,
 +  .message .message-header .unlock-dialog .message-close-button:insensitive,
 +  .unlock-dialog .screenshot-ui-show-pointer-button:insensitive,
 +  .unlock-dialog .login-dialog-button.cancel-button:insensitive,
 +  .unlock-dialog .login-dialog-button.switch-user-button:insensitive,
 +  .unlock-dialog .login-dialog-button.login-dialog-session-list-button:insensitive {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(137, 179, 231, 0.145);
++    color: st-transparentize(whitesmoke, 0.6);
++    background-color: st-lighten(st-mix(whitesmoke, whitesmoke, 12%), 3%); }
 +
 +.unlock-dialog .login-dialog-prompt-entry {
 +  background-color: rgba(245, 245, 245, 0.1);
 +  color: rgba(245, 245, 245, 0.7); }
 +  .unlock-dialog .login-dialog-prompt-entry:hover {
 +    background-color: rgba(255, 255, 255, 0.1);
 +    color: whitesmoke; }
 +  .unlock-dialog .login-dialog-prompt-entry:focus {
-     background-color: rgba(245, 245, 245, 0.115); }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(245, 245, 245, 0.1), 5%);
 +    color: whitesmoke;
 +    box-shadow: inset 0 0 0 2px rgba(245, 245, 245, 0.4) !important;
-   color: #1c71d8; }
++    background-color: st-mix(rgba(245, 245, 245, 0.4), rgba(245, 245, 245, 0.1), 5%); }
 +  .unlock-dialog .login-dialog-prompt-entry:insensitive {
 +    background-color: rgba(237, 237, 237, 0.1);
 +    color: rgba(245, 245, 245, 0.5); }
 +  .unlock-dialog .login-dialog-prompt-entry StLabel.hint-text {
 +    color: rgba(245, 245, 245, 0.7); }
 +
 +/* WIDGETS */
 +.shell-link {
-     color: #418ce6; }
++  color: st-darken(-st-accent-color, 10%); }
 +  .shell-link:hover {
-   width: 24px;
-   height: 24px;
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-off-light.svg"); }
++    color: st-lighten(st-darken(-st-accent-color, 10%), 10%); }
 +
 +.lowres-icon {
 +  icon-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); }
 +
 +.icon-dropshadow {
 +  icon-shadow: 0 2px 4px rgba(0, 0, 0, 0.4); }
 +
 +/* Entries */
 +StEntry StIcon.capslock-warning {
 +  icon-size: 1.091em;
 +  warning-color: #f5c211;
 +  padding: 0 4px; }
 +
 +StEntry StIcon.peek-password {
 +  icon-size: 1.091em;
 +  padding: 0 4px; }
 +
 +StEntry StLabel.hint-text {
 +  margin-left: 2px; }
 +
 +/* Buttons */
 +.button {
 +  min-height: 1.5em; }
 +
 +.icon-button, .login-dialog-button.cancel-button, .login-dialog-button.switch-user-button, .login-dialog-button.login-dialog-session-list-button, .screenshot-ui-show-pointer-button, .message .message-header .message-expand-button,
 +.message .message-header .message-close-button, .calendar .calendar-month-header .pager-button {
 +  border-radius: 999px;
 +  padding: 0.818em;
 +  min-height: 1.091em; }
 +  .icon-button StIcon, .login-dialog-button.cancel-button StIcon, .login-dialog-button.switch-user-button StIcon, .login-dialog-button.login-dialog-session-list-button StIcon, .screenshot-ui-show-pointer-button StIcon, .message .message-header .message-expand-button StIcon,
 +  .message .message-header .message-close-button StIcon, .calendar .calendar-month-header .pager-button StIcon {
 +    icon-size: 1.091em;
 +    -st-icon-style: symbolic; }
 +
 +/* Check Boxes */
 +.check-box StBoxLayout {
 +  spacing: .8em; }
 +
 +.check-box StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-off-focused-light.svg"); }
++  border-radius: 7px;
++  padding: 2px; }
 +
 +.check-box:focus StBin {
- .check-box:checked StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); }
++  background-color: rgba(0, 0, 0, 0.01);
++  box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.65); }
++
++.check-box StIcon {
++  icon-size: 14px;
++  padding: 1px;
++  color: transparent;
++  border-radius: 6px;
++  border: 2px solid rgba(0, 0, 0, 0.15); }
++
++.check-box:hover StIcon {
++  border-color: rgba(0, 0, 0, 0.2); }
++
++.check-box:active StIcon {
++  border-color: rgba(0, 0, 0, 0.3); }
 +
- .check-box:focus:checked StBin {
-   background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); }
++.check-box:checked StIcon {
++  background-color: -st-accent-color;
++  color: -st-accent-fg-color;
++  border-color: transparent; }
 +
-   color: #282828;
-   height: 26px;
++.check-box:checked:hover StIcon {
++  background-color: st-lighten(-st-accent-color, 5%);
++  color: st-lighten(-st-accent-fg-color, 5%); }
++
++.check-box:checked:active StIcon {
++  background-color: st-darken(-st-accent-color, 7%);
++  color: st-darken(-st-accent-fg-color, 7%); }
 +
 +/* Switches */
 +.toggle-switch {
-   background-size: contain;
-   background-image: url("resource:///org/gnome/shell/theme/toggle-off-light.svg"); }
-   .toggle-switch:checked {
-     background-image: url("resource:///org/gnome/shell/theme/toggle-on-light.svg"); }
 +  width: 46px;
-   -barlevel-background-color: rgba(40, 40, 40, 0.2);
-   -barlevel-border-width: 2px;
-   -barlevel-border-color: transparent;
-   -barlevel-active-background-color: #1c71d8;
-   -barlevel-active-border-color: transparent;
++  border-radius: 999px;
++  transition-duration: 100ms;
++  color: #282828;
++  background: rgba(0, 0, 0, 0.15); }
++  .toggle-switch:hover {
++    background: rgba(0, 0, 0, 0.2); }
 +  .toggle-switch StIcon {
 +    icon-size: 16px; }
++  .toggle-switch .handle {
++    margin: 3px;
++    width: 20px;
++    height: 20px;
++    border-radius: 999px;
++    background: white;
++    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
++    transition-duration: 100ms; }
++  .toggle-switch:checked {
++    background: -st-accent-color;
++    color: -st-accent-fg-color; }
++    .toggle-switch:checked:hover {
++      background-color: st-lighten(-st-accent-color, 5%);
++      color: st-lighten(-st-accent-fg-color, 5%); }
++    .toggle-switch:checked .handle {
++      background: white; }
 +
 +/* Slider */
 +.slider {
++  color: #282828;
 +  -barlevel-height: 4px;
-   -barlevel-overdrive-border-color: transparent;
++  -barlevel-background-color: rgba(40, 40, 40, 0.1);
++  -barlevel-active-background-color: -st-accent-color;
 +  -barlevel-overdrive-color: #e01b24;
-   -slider-handle-radius: 0.5455em;
-   -slider-handle-border-width: 0;
-   -slider-handle-border-color: transparent; }
 +  -barlevel-overdrive-separator-width: 1px;
-   .popup-menu-item:focus, .popup-menu-item:hover {
++  -slider-handle-radius: 0.5455em; }
++  .slider:hover {
++    color: #3a3a3a; }
 +
 +/* Scrollbars */
 +StScrollView.vfade {
 +  -st-vfade-offset: 68px; }
 +
 +StScrollView.hfade {
 +  -st-hfade-offset: 68px; }
 +
 +StScrollBar {
 +  padding: 0; }
 +  StScrollView StScrollBar {
 +    min-width: 8px;
 +    min-height: 8px; }
 +  StScrollBar StBin#trough {
 +    border-radius: 0;
 +    background-color: transparent; }
 +  StScrollBar StButton#vhandle, StScrollBar StButton#hhandle {
 +    border-radius: 8px;
 +    background-color: #b8b8b8;
 +    border: 3px solid transparent;
 +    transition: 500ms all ease; }
 +    StScrollBar StButton#vhandle:hover, StScrollBar StButton#hhandle:hover {
 +      background-color: #8f8f8f; }
 +    StScrollBar StButton#vhandle:active, StScrollBar StButton#hhandle:active {
 +      background-color: #a3a3a3; }
 +
 +/* Popovers/Menus */
 +.popup-menu-boxpointer, .candidate-popup-boxpointer {
 +  -arrow-rise: 6px; }
 +
 +.popup-menu {
 +  min-width: 15em;
 +  color: #282828; }
 +  .popup-menu.panel-menu {
 +    margin-bottom: 1.75em; }
 +
 +.popup-menu-content, .candidate-popup-content {
 +  padding: 6px;
 +  background-color: whitesmoke;
 +  border-radius: 20px;
 +  border: 1px solid #e3e3e3;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.05); }
 +
 +.popup-menu-item {
 +  background-color: transparent;
 +  border-color: transparent;
 +  box-shadow: none;
 +  border-radius: 12px; }
 +  .popup-menu-item:insensitive {
 +    background-color: transparent !important; }
-     background-color: #c7c7c7; }
++  .popup-menu-item:hover {
 +    color: #282828;
-     background-color: #bababa; }
++    background-color: st-darken(st-mix(#282828, #e8e8e8, 12%), 4%); }
 +  .popup-menu-item:active {
 +    color: #282828;
-       background-color: #b0b0b0; }
++    background-color: st-darken(st-mix(#282828, #e8e8e8, 12%), 9%); }
 +    .popup-menu-item:active:hover {
-       background-color: #b2b6bc; }
-   .popup-menu-item:checked {
++      background-color: st-darken(st-darken(st-mix(#282828, #e8e8e8, 12%), 9%), 4%); }
 +    .popup-menu-item:active:focus {
-     background-color: #bdbdbd; }
-     .popup-menu-item:checked:hover {
-       background-color: #b2b2b2; }
-     .popup-menu-item:checked:active {
-       background-color: #a6a6a6; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, #e8e8e8, 12%), 9%), 5%); }
++  .popup-menu-item:selected, .popup-menu-item:checked {
 +    color: #282828;
-     color: rgba(40, 40, 40, 0.4);
-     background-color: #d9d9d9; }
++    background-color: st-darken(st-mix(#282828, #e8e8e8, 12%), 8%); }
++    .popup-menu-item:selected:hover, .popup-menu-item:checked:hover {
++      background-color: st-darken(st-darken(st-mix(#282828, #e8e8e8, 12%), 8%), 4%); }
++    .popup-menu-item:selected:active, .popup-menu-item:checked:active {
++      background-color: st-darken(st-darken(st-mix(#282828, #e8e8e8, 12%), 8%), 9%); }
 +  .popup-menu-item:insensitive {
-     .popup-sub-menu .popup-menu-item:focus, .popup-sub-menu .popup-menu-item:hover {
++    color: st-transparentize(#282828, 0.6);
++    background-color: st-lighten(st-mix(#282828, #e8e8e8, 12%), 3%); }
 +  .popup-menu-item:checked {
 +    border-radius: 12px 12px 0 0 !important; }
 +  .popup-menu-item .toggle-switch:ltr {
 +    margin-left: 4px; }
 +  .popup-menu-item .toggle-switch:rtl {
 +    margin-right: 4px; }
 +
 +.popup-ornamented-menu-item:ltr {
 +  padding-left: 6px; }
 +
 +.popup-ornamented-menu-item:rtl {
 +  padding-right: 6px; }
 +
 +.popup-inactive-menu-item {
 +  color: #282828; }
 +  .popup-inactive-menu-item:insensitive {
 +    color: #7a7a7a; }
 +
 +.popup-menu-arrow,
 +.popup-menu-icon {
 +  icon-size: 1.091em; }
 +
 +.popup-sub-menu {
 +  border-radius: 0 0 13px 13px;
 +  margin-bottom: 6px;
 +  border: 1px solid transparent;
 +  background-color: #cacaca; }
 +  .popup-sub-menu .popup-menu-item {
 +    border-radius: 0;
 +    border-top-width: 0;
 +    background-color: transparent;
 +    border-color: transparent;
 +    box-shadow: none; }
 +    .popup-sub-menu .popup-menu-item:insensitive {
 +      background-color: transparent !important; }
-       background-color: #acacac; }
++    .popup-sub-menu .popup-menu-item:hover {
 +      color: #282828;
-       background-color: #9f9f9f; }
++      background-color: st-darken(st-mix(#282828, #cacaca, 12%), 4%); }
 +    .popup-sub-menu .popup-menu-item:active {
 +      color: #282828;
-         background-color: #959595; }
++      background-color: st-darken(st-mix(#282828, #cacaca, 12%), 9%); }
 +      .popup-sub-menu .popup-menu-item:active:hover {
-         background-color: #989da2; }
-     .popup-sub-menu .popup-menu-item:checked {
++        background-color: st-darken(st-darken(st-mix(#282828, #cacaca, 12%), 9%), 4%); }
 +      .popup-sub-menu .popup-menu-item:active:focus {
-       background-color: #a2a2a2; }
-       .popup-sub-menu .popup-menu-item:checked:hover {
-         background-color: #979797; }
-       .popup-sub-menu .popup-menu-item:checked:active {
-         background-color: #8b8b8b; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, #cacaca, 12%), 9%), 5%); }
++    .popup-sub-menu .popup-menu-item:selected, .popup-sub-menu .popup-menu-item:checked {
 +      color: #282828;
-       color: rgba(40, 40, 40, 0.4);
-       background-color: #bebebe; }
++      background-color: st-darken(st-mix(#282828, #cacaca, 12%), 8%); }
++      .popup-sub-menu .popup-menu-item:selected:hover, .popup-sub-menu .popup-menu-item:checked:hover {
++        background-color: st-darken(st-darken(st-mix(#282828, #cacaca, 12%), 8%), 4%); }
++      .popup-sub-menu .popup-menu-item:selected:active, .popup-sub-menu .popup-menu-item:checked:active {
++        background-color: st-darken(st-darken(st-mix(#282828, #cacaca, 12%), 8%), 9%); }
 +    .popup-sub-menu .popup-menu-item:insensitive {
-       color: #ffffff !important; }
++      color: st-transparentize(#282828, 0.6);
++      background-color: st-lighten(st-mix(#282828, #cacaca, 12%), 3%); }
 +    .popup-sub-menu .popup-menu-item:last-child {
 +      border-radius: 0 0 12px 12px;
 +      border-bottom-width: 0; }
 +  .popup-sub-menu .popup-menu-section .popup-menu-item:last-child:hover, .popup-sub-menu .popup-menu-section .popup-menu-item:last-child:focus {
 +    border-radius: 0; }
 +  .popup-sub-menu .popup-menu-section:last-child .popup-menu-item:last-child {
 +    border-radius: 0 0 12px 12px; }
 +
 +.popup-menu-ornament {
 +  icon-size: 1.091em !important;
 +  width: 1.091em; }
 +
 +.popup-separator-menu-item {
 +  border: none !important; }
 +  .popup-separator-menu-item .popup-separator-menu-item-separator {
 +    height: 1px;
 +    background-color: rgba(40, 40, 40, 0.15); }
 +  .popup-sub-menu .popup-separator-menu-item {
 +    background-color: transparent; }
 +    .popup-sub-menu .popup-separator-menu-item:ltr {
 +      margin-right: 2.5em; }
 +    .popup-sub-menu .popup-separator-menu-item:rtl {
 +      margin-left: 2.5em; }
 +    .popup-sub-menu .popup-separator-menu-item .popup-separator-menu-item-separator {
 +      background-color: rgba(40, 40, 40, 0.15); }
 +
 +.background-menu {
 +  -boxpointer-gap: 0px;
 +  -arrow-rise: 0px; }
 +
 +.app-menu {
 +  max-width: 27.25em; }
 +  .app-menu .popup-inactive-menu-item:first-child > StLabel:ltr {
 +    margin-right: 8px; }
 +  .app-menu .popup-inactive-menu-item:first-child > StLabel:rtl {
 +    margin-left: 8px; }
 +
 +/* Date/Time Menu */
 +#calendarArea {
 +  padding: 4px; }
 +
 +.datemenu-popover {
 +  border-radius: 30px; }
 +
 +.datemenu-calendar-column {
 +  spacing: 6px; }
 +  .datemenu-calendar-column:ltr {
 +    margin-left: 6px; }
 +  .datemenu-calendar-column:rtl {
 +    margin-right: 6px; }
 +  .datemenu-calendar-column .datemenu-displays-box {
 +    spacing: 6px; }
 +
 +.datemenu-today-button {
 +  padding: 9px; }
 +  .datemenu-today-button .day-label {
 +    font-weight: bold; }
 +
 +.calendar {
 +  margin-top: 0;
 +  padding: 0; }
 +  .calendar .calendar-month-header .calendar-change-month-back StIcon,
 +  .calendar .calendar-month-header .calendar-change-month-forward StIcon {
 +    icon-size: 1.091em; }
 +  .calendar .calendar-month-header .calendar-month-label {
 +    color: #282828 !important;
 +    padding: 8px 0;
 +    width: 10em;
 +    border-radius: 999px;
 +    text-align: center; }
 +  .calendar .calendar-month-header .pager-button {
 +    height: 2.6em;
 +    width: 2.6em;
 +    padding: 0; }
 +  .calendar .calendar-day {
 +    border-radius: 999px;
 +    height: 3em;
 +    width: 3em;
 +    margin: 2px;
 +    padding: 0;
 +    font-weight: bold;
 +    text-align: center; }
 +    .calendar .calendar-day.calendar-weekend {
 +      color: #7a7a7a; }
 +    .calendar .calendar-day.calendar-other-month {
 +      color: rgba(40, 40, 40, 0.5);
 +      font-weight: normal; }
 +      .calendar .calendar-day.calendar-other-month.calendar-weekend {
 +        color: rgba(40, 40, 40, 0.5); }
 +    .calendar .calendar-day.calendar-today {
-       border-color: rgba(28, 113, 216, 0.6); }
++      color: -st-accent-fg-color !important; }
 +      .calendar .calendar-day.calendar-today.calendar-day-with-events {
 +        background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg") !important; }
 +    .calendar .calendar-day.calendar-day-with-events {
 +      background-image: url("resource:///org/gnome/shell/theme/calendar-today-light.svg");
 +      background-size: contain; }
 +  .calendar .calendar-day-heading {
 +    font-weight: bold;
 +    text-align: center;
 +    margin: 4px;
 +    padding: 3px 6px;
 +    border-radius: 8px; }
 +  .calendar .calendar-week-number {
 +    font-weight: bold;
 +    font-feature-settings: "tnum";
 +    text-align: center;
 +    margin: 6px;
 +    padding: 0 6px;
 +    border-radius: 4px;
 +    background-color: rgba(122, 122, 122, 0.2);
 +    color: #7a7a7a; }
 +
 +.events-button .events-box .events-title {
 +  color: #7a7a7a;
 +  padding-bottom: 6px; }
 +
 +.events-button .events-box .events-list {
 +  spacing: 6px; }
 +  .events-button .events-box .events-list .event-box {
 +    spacing: 6px;
 +    border-radius: 8px; }
 +    .events-button .events-box .events-list .event-box .event-time {
 +      color: #7a7a7a; }
 +  .events-button .events-box .events-list .event-placeholder {
 +    color: #7a7a7a;
 +    font-style: italic; }
 +
 +.world-clocks-button .world-clocks-header {
 +  color: #7a7a7a; }
 +  .world-clocks-button .world-clocks-header.no-world-clocks {
 +    color: #282828; }
 +
 +.world-clocks-button .world-clocks-grid {
 +  spacing-rows: 6px;
 +  spacing-columns: 12px; }
 +  .world-clocks-button .world-clocks-grid .world-clocks-time {
 +    font-weight: bold; }
 +    .world-clocks-button .world-clocks-grid .world-clocks-time:ltr {
 +      text-align: right; }
 +    .world-clocks-button .world-clocks-grid .world-clocks-time:rtl {
 +      text-align: left; }
 +  .world-clocks-button .world-clocks-grid .world-clocks-timezone {
 +    color: #7a7a7a; }
 +
 +.weather-button .weather-box {
 +  spacing: 6px; }
 +  .weather-button .weather-box .weather-header-box {
 +    spacing: 6px; }
 +    .weather-button .weather-box .weather-header-box .weather-header {
 +      color: #7a7a7a; }
 +      .weather-button .weather-box .weather-header-box .weather-header.no-location {
 +        color: #282828; }
 +      .weather-button .weather-box .weather-header-box .weather-header.location {
 +        font-weight: normal; }
 +  .weather-button .weather-box .weather-grid {
 +    spacing-rows: 6px;
 +    spacing-columns: 12px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-time {
 +      padding-top: 6px;
 +      padding-bottom: 6px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-icon {
 +      icon-size: 2.182em;
 +      margin-bottom: 4px; }
 +    .weather-button .weather-box .weather-grid .weather-forecast-temp {
 +      font-weight: bold; }
 +
 +/* Message List */
 +.message-list {
 +  width: 29em;
 +  border: solid rgba(40, 40, 40, 0.15); }
 +  .message-list:ltr {
 +    margin-left: 0;
 +    margin-right: 4px;
 +    padding-right: 6px;
 +    border-right-width: 1px; }
 +  .message-list:rtl {
 +    margin-right: 0;
 +    margin-left: 4px;
 +    padding-left: 6px;
 +    border-left-width: 1px; }
 +  .message-list .message-list-placeholder {
 +    color: rgba(40, 40, 40, 0.25); }
 +    .message-list .message-list-placeholder > StIcon {
 +      icon-size: 96px;
 +      margin-bottom: 12px;
 +      -st-icon-style: symbolic; }
 +
 +.message-list-sections {
 +  spacing: 12px; }
 +  .message-list-sections:ltr {
 +    margin-right: 12px; }
 +  .message-list-sections:rtl {
 +    margin-left: 12px; }
 +
 +.message-list-section,
 +.message-list-section-list {
 +  spacing: 12px; }
 +
 +.message-list-controls {
 +  padding: 12px;
 +  padding-bottom: 6px;
 +  spacing: 6px; }
 +  .message-list-controls .dnd-button {
 +    border-width: 2px;
 +    border-color: transparent;
 +    border-radius: 32px;
 +    border-style: solid; }
 +    .message-list-controls .dnd-button:focus {
-   padding: 0;
++      border-color: st-transparentize(-st-accent-color, 0.4); }
 +
 +.message {
-   .message:ltr {
-     padding-right: -2px; }
-   .message:rtl {
-     padding-left: -2px; }
++  padding: 6px;
 +  margin: 0;
 +  border-radius: 16px; }
-     padding: 0 0.409em;
-     margin: 6px;
-     margin-bottom: 0;
 +  .message .message-header {
-     color: #7a7a7a; }
 +    spacing: 6px;
-       background-color: rgba(40, 40, 40, 0.1);
++    color: #7a7a7a;
++    padding: 0 6px; }
++    .message .message-header:ltr {
++      padding-right: 4px; }
++    .message .message-header:rtl {
++      padding-left: 4px; }
 +    .message .message-header .message-source-icon {
 +      icon-size: 1.091em;
 +      -st-icon-style: symbolic; }
 +    .message .message-header .message-header-content {
 +      spacing: 6px;
 +      min-height: 1.637em;
 +      padding-bottom: 6px; }
 +      .message .message-header .message-header-content .message-source-title {
 +        font-weight: bold; }
 +      .message .message-header .message-header-content .event-time {
 +        color: #7a7a7a;
 +        padding-bottom: 0.068em; }
 +        .message .message-header .message-header-content .event-time:ltr {
 +          text-align: right; }
 +        .message .message-header .message-header-content .event-time:rtl {
 +          text-align: left; }
 +    .message .message-header .message-expand-button,
 +    .message .message-header .message-close-button {
++      border-radius: 999px;
 +      color: #282828;
-       .message .message-header .message-expand-button:hover,
-       .message .message-header .message-close-button:hover {
-         background-color: rgba(40, 40, 40, 0.19); }
-       .message .message-header .message-expand-button:active, .message .message-header .message-expand-button:active:hover,
-       .message .message-header .message-close-button:active,
-       .message .message-header .message-close-button:active:hover {
-         background-color: rgba(40, 40, 40, 0.24); }
-       .message .message-header .message-expand-button:insensitive,
-       .message .message-header .message-close-button:insensitive {
-         background-color: rgba(40, 40, 40, 0.07); }
 +      padding: 4px; }
-     margin: 6px;
 +    .message .message-header .message-expand-button {
 +      padding: 6px; }
 +      .message .message-header .message-expand-button:ltr {
 +        margin-right: 6px; }
 +      .message .message-header .message-expand-button:rtl {
 +        margin-left: 6px; }
 +  .message .message-box {
 +    padding: 6px;
-   link-color: #1c71d8; }
 +    margin-top: 0;
 +    spacing: 6px; }
 +    .message .message-box .message-icon {
 +      icon-size: 48px; }
 +      .message .message-box .message-icon:ltr {
 +        margin-right: 6px; }
 +      .message .message-box .message-icon:rtl {
 +        margin-left: 6px; }
 +      .message .message-box .message-icon.message-themed-icon {
 +        border-radius: 999px;
 +        background-color: rgba(40, 40, 40, 0.07);
 +        icon-size: 1.091em;
 +        min-width: 48px;
 +        min-height: 48px; }
 +    .message .message-box:first-child {
 +      margin-top: 12px; }
 +    .message .message-box .message-content {
 +      spacing: 4px; }
 +      .message .message-box .message-content .message-title {
 +        font-weight: bold; }
++  .message .message-action-bin {
++    padding: 4px;
++    spacing: 6px; }
++    .message .message-action-bin * {
++      margin: 0 4px; }
++      .message .message-action-bin *:first-child:ltr {
++        margin-left: 0; }
++      .message .message-action-bin *:first-child:rtl {
++        margin-right: 0; }
++      .message .message-action-bin *:last-child:ltr {
++        margin-right: 0; }
++      .message .message-action-bin *:last-child:rtl {
++        margin-left: 0; }
 +
 +.url-highlighter {
-     background-color: #1c71d8;
-     color: #ffffff; }
++  link-color: st-darken(-st-accent-color, 10%); }
 +
 +/* Media Controls */
 +.message-media-control {
 +  padding: 0 18px;
 +  border-radius: 8px;
 +  color: #282828;
 +  border: 1px solid transparent; }
 +  .message-media-control:hover {
 +    background-color: #ebebeb;
 +    color: #282828; }
 +  .message-media-control:active {
 +    background-color: #e6e6e6;
 +    color: #282828; }
 +  .message-media-control:insensitive {
 +    color: #878787; }
 +  .message-media-control StIcon {
 +    icon-size: 16px; }
 +
 +.media-message .message-icon {
 +  border-radius: 8px !important; }
 +  .media-message .message-icon.message-themed-icon {
 +    icon-size: 32px !important; }
 +
 +.candidate-popup-content {
 +  padding: 6px;
 +  spacing: 6px; }
 +
 +.candidate-index {
 +  padding: 0;
 +  padding-right: 6px;
 +  color: #7a7a7a; }
 +
 +.candidate-box {
 +  padding: 6px 12px 6px 12px;
 +  border-radius: 8px; }
 +  .candidate-box:selected {
-   border-radius: 16px;
-   box-shadow: inset 0 0 0 1px #e3e3e3; }
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +  .candidate-box:hover {
 +    background-color: #dedede;
 +    color: #111111; }
 +
 +.candidate-page-button-box {
 +  height: 2em; }
 +  .vertical .candidate-page-button-box {
 +    padding-top: 12px; }
 +  .horizontal .candidate-page-button-box {
 +    padding-left: 12px; }
 +
 +.candidate-page-button {
 +  padding: 6px; }
 +  .candidate-page-button StIcon {
 +    icon-size: 16px; }
 +
 +.candidate-page-button-previous {
 +  border-radius: 8px 0px 0px 8px;
 +  border-right-width: 0;
 +  box-shadow: none; }
 +
 +.candidate-page-button-next {
 +  border-radius: 0px 8px 8px 0px;
 +  box-shadow: none; }
 +
 +/* Notifications & Message Tray */
 +.notification-banner {
 +  min-height: 64px;
 +  width: 34em;
 +  box-shadow: 0 2px 4px 2px rgba(0, 0, 0, 0.05);
 +  border-radius: 16px;
 +  margin: 4px; }
 +
 +.notification-buttons-bin {
 +  spacing: 0; }
 +
 +/* Modal Dialogs */
 +.modal-dialog {
 +  background-color: whitesmoke;
-     margin: 32px 40px;
++  border-radius: 18px;
++  box-shadow: inset 0 0 0 1px #e3e3e3;
++  padding: 24px; }
 +  .modal-dialog .modal-dialog-content-box {
-   width: 30em; }
 +    spacing: 32px;
++    margin-top: 8px;
++    margin-bottom: 16px;
 +    max-width: 28em; }
 +
 +/* End Session Dialog */
 +.end-session-dialog {
-     background-color: #1c71d8;
-     color: #ffffff; }
++  width: 24em; }
 +  .end-session-dialog .end-session-dialog-battery-warning,
 +  .end-session-dialog .dialog-list-title {
 +    color: #f5c211; }
 +
 +/* Message Dialog */
 +.message-dialog-content {
 +  spacing: 18px; }
 +  .message-dialog-content .message-dialog-title {
 +    text-align: center; }
 +  .message-dialog-content .message-dialog-description {
 +    text-align: center; }
 +
 +/* Dialog List */
 +.dialog-list {
 +  spacing: 18px; }
 +  .dialog-list .dialog-list-title {
 +    text-align: center; }
 +  .dialog-list .dialog-list-scrollview {
 +    max-height: 200px; }
 +  .dialog-list .dialog-list-box {
 +    spacing: 1em; }
 +    .dialog-list .dialog-list-box .dialog-list-item {
 +      spacing: 1em; }
 +      .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-title {
 +        font-weight: bold; }
 +      .dialog-list .dialog-list-box .dialog-list-item .dialog-list-item-description {
 +        color: #1b1b1b; }
 +
 +/* Run Dialog */
 +.run-dialog .modal-dialog-content-box {
 +  margin-top: 24px;
 +  margin-bottom: 12px; }
 +
 +.run-dialog .run-dialog-entry {
 +  width: 20em; }
 +
 +.run-dialog .run-dialog-description {
 +  text-align: center;
 +  color: black; }
 +
 +/* Password or Authentication Dialog */
 +.prompt-dialog {
 +  width: 28em; }
 +  .prompt-dialog .modal-dialog-content-box {
 +    margin-bottom: 24px; }
 +
 +.prompt-dialog-password-grid {
 +  spacing-rows: 8px;
 +  spacing-columns: 4px; }
 +  .prompt-dialog-password-grid .prompt-dialog-password-entry {
 +    width: auto; }
 +    .prompt-dialog-password-grid .prompt-dialog-password-entry:ltr {
 +      margin-left: 20px; }
 +    .prompt-dialog-password-grid .prompt-dialog-password-entry:rtl {
 +      margin-right: 20px; }
 +
 +.prompt-dialog-password-layout {
 +  spacing: 8px; }
 +
 +.prompt-dialog-password-entry {
 +  width: 20em; }
 +
 +.prompt-dialog-error-label,
 +.prompt-dialog-info-label,
 +.prompt-dialog-null-label {
 +  text-align: center; }
 +
 +.prompt-dialog-error-label {
 +  color: #f5c211; }
 +
 +/* Polkit Dialog */
 +.polkit-dialog-user-layout {
 +  text-align: center;
 +  spacing: 8px;
 +  margin-bottom: 6px; }
 +  .polkit-dialog-user-layout .polkit-dialog-user-root-label {
 +    color: #f5c211; }
 +
 +/* Audio selection dialog */
 +.audio-device-selection-dialog .modal-dialog-content-box {
 +  margin-bottom: 28px; }
 +
 +.audio-device-selection-dialog .audio-selection-box {
 +  spacing: 20px; }
 +
 +.audio-selection-device {
 +  border-radius: 16px; }
 +  .audio-selection-device:hover, .audio-selection-device:focus {
 +    background-color: #dedede; }
 +  .audio-selection-device:active {
-   background-color: #1c71d8;
-   color: #ffffff;
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +
 +.audio-selection-device-box {
 +  padding: 20px;
 +  spacing: 20px; }
 +
 +.audio-selection-device-icon {
 +  icon-size: 64px; }
 +
 +/* Welcome dialog */
 +.welcome-dialog-image {
 +  background-image: url("resource:///org/gnome/shell/theme/gnome-shell-start.svg");
 +  background-size: contain;
 +  /* Reasonable maximum dimensions */
 +  height: 300px;
 +  width: 300px; }
 +
 +/* Access portal dialog */
 +.access-dialog {
 +  text-align: center; }
 +
 +/* OSD */
 +.osd-window {
 +  text-align: center;
 +  font-weight: bold;
 +  spacing: 12px;
 +  padding: 12px 18px;
 +  margin-bottom: 4em; }
 +  .osd-window > * {
 +    spacing: 8px; }
 +  .osd-window StIcon {
 +    icon-size: 32px; }
 +  .osd-window StLabel:ltr {
 +    margin-right: 6px; }
 +  .osd-window StLabel:rtl {
 +    margin-left: 6px; }
 +  .osd-window .level {
 +    margin-bottom: 4px;
 +    min-width: 160px;
 +    -barlevel-height: 6px;
 +    -barlevel-background-color: rgba(255, 255, 255, 0.3);
 +    -barlevel-active-background-color: #ffffff;
 +    -barlevel-overdrive-color: #e01b24;
 +    -barlevel-overdrive-separator-width: 3px; }
 +    .osd-window .level:first-child {
 +      margin-bottom: 0; }
 +    .osd-window .level:ltr {
 +      margin-right: 6px; }
 +    .osd-window .level:rtl {
 +      margin-left: 6px; }
 +
 +.osd-monitor-label {
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-       background-color: rgba(46, 69, 97, 0.2875); }
++  background-color: -st-accent-color;
++  color: -st-accent-fg-color;
 +  border-radius: 16px;
 +  font-size: 3em;
 +  font-weight: bold;
 +  font-feature-settings: "tnum";
 +  margin: 12px;
 +  padding: 12px;
 +  text-align: center;
 +  min-width: 1.5em; }
 +
 +/* Pad OSD */
 +.pad-osd-window {
 +  padding: 32px;
 +  background-color: rgba(0, 0, 0, 0.8); }
 +  .pad-osd-window .pad-osd-title-box {
 +    spacing: 12px; }
 +  .pad-osd-window .pad-osd-title-menu-box {
 +    spacing: 6px; }
 +
 +.combo-box-label {
 +  width: 15em; }
 +
 +/* App Switcher */
 +.switcher-popup {
 +  padding: 0;
 +  spacing: 24px; }
 +
 +.switcher-list {
 +  padding: 12px;
 +  border-radius: 28px;
 +  box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.05); }
 +  .switcher-list .switcher-list-item-container {
 +    spacing: 12px; }
 +  .switcher-list .item-box {
 +    color: #ffffff;
 +    background-color: #353535; }
 +    .switcher-list .item-box:focus {
 +      color: #ffffff;
-         background-color: #44494e; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, rgba(53, 53, 53, 0.25), 5%); }
 +      .switcher-list .item-box:focus:hover {
-       background-color: #474747; }
++        background-color: st-mix(-st-accent-color, st-lighten(#353535, 7%), 5%); }
 +    .switcher-list .item-box:hover {
 +      color: #ffffff;
-       background-color: #4c4c4c; }
++      background-color: st-lighten(#353535, 7%); }
 +    .switcher-list .item-box:active {
 +      color: #ffffff;
-         background-color: #5e5e5e; }
++      background-color: st-lighten(#353535, 9%); }
 +      .switcher-list .item-box:active:hover {
-         background-color: #494e53; }
++        background-color: st-lighten(st-lighten(#353535, 9%), 7%); }
 +      .switcher-list .item-box:active:focus {
-       background-color: #494949; }
++        background-color: st-mix(-st-accent-color, st-lighten(#353535, 9%), 5%); }
 +    .switcher-list .item-box:highlighted, .switcher-list .item-box:selected, .switcher-list .item-box:checked {
 +      color: #ffffff;
-         background-color: #5b5b5b; }
++      background-color: st-lighten(#353535, 8%); }
 +      .switcher-list .item-box:highlighted:hover, .switcher-list .item-box:selected:hover, .switcher-list .item-box:checked:hover {
-         background-color: #606060; }
++        background-color: st-lighten(st-lighten(#353535, 8%), 7%); }
 +      .switcher-list .item-box:highlighted:active, .switcher-list .item-box:selected:active, .switcher-list .item-box:checked:active {
-       color: rgba(255, 255, 255, 0.4);
++        background-color: st-lighten(st-lighten(#353535, 8%), 9%); }
 +    .switcher-list .item-box:insensitive {
-       background-color: rgba(28, 113, 216, 0.2);
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.8); }
++      color: st-transparentize(#ffffff, 0.6);
 +      background-color: #353535; }
 +    .switcher-list .item-box:drop {
-   border: 5px solid #1c71d8; }
++      background-color: st-transparentize(-st-accent-color, 0.8);
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +    .switcher-list .item-box:hover {
 +      background: none; }
 +    .switcher-list .item-box:selected {
 +      background-color: rgba(255, 255, 255, 0.2); }
 +  .switcher-list .separator {
 +    width: 1px;
 +    background: rgba(40, 40, 40, 0.15); }
 +  .switcher-list .thumbnail-box {
 +    padding: 2px;
 +    spacing: 6px; }
 +  .switcher-list .thumbnail {
 +    width: 256px;
 +    border-radius: 8px; }
 +
 +.switcher-arrow {
 +  border-color: rgba(255, 255, 255, 0.8);
 +  color: rgba(255, 255, 255, 0.8); }
 +  .switcher-arrow:highlighted {
 +    border-color: #ffffff;
 +    color: #ffffff; }
 +
 +.input-source-switcher-symbol {
 +  font-size: 34pt;
 +  width: 96px;
 +  height: 96px; }
 +
 +.cycler-highlight {
-   border-color: #134e94; }
++  border: 5px solid -st-accent-color; }
 +
 +/* Workspace Switcher */
 +.workspace-switcher {
 +  margin-bottom: 4em;
 +  spacing: 12px;
 +  padding: 12px 18px; }
 +
 +.ws-switcher-indicator {
 +  background-color: rgba(255, 255, 255, 0.5);
 +  padding: 2.6666666667px;
 +  margin: 13.3333333333px;
 +  border-radius: 32px; }
 +  .ws-switcher-indicator:active {
 +    background-color: #ffffff;
 +    padding: 5.3333333333px;
 +    margin: 10.6666666667px; }
 +
 +.screenshot-ui-panel {
 +  border-radius: 32px;
 +  padding: 18px;
 +  padding-bottom: 12px;
 +  margin-bottom: 4em;
 +  spacing: 12px; }
 +
 +.screenshot-ui-close-button {
 +  padding: 6px !important;
 +  margin-top: 12px;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.05); }
 +  .screenshot-ui-close-button.left {
 +    margin-left: 12px; }
 +  .screenshot-ui-close-button.right {
 +    margin-right: 12px; }
 +
 +.screenshot-ui-type-button {
 +  min-width: 48px;
 +  padding: 12px 18px;
 +  border-radius: 14px; }
 +  .screenshot-ui-type-button .icon-label-button-container {
 +    spacing: 0.409em; }
 +    .screenshot-ui-type-button .icon-label-button-container > StIcon {
 +      icon-size: 32px; }
 +
 +.screenshot-ui-capture-button {
 +  width: 32px;
 +  height: 32px;
 +  border-radius: 999px;
 +  border: 4px #ffffff;
 +  padding: 4px; }
 +  .screenshot-ui-capture-button .screenshot-ui-capture-button-circle {
 +    background-color: #ffffff;
 +    transition-duration: 200ms;
 +    border-radius: 999px; }
 +    .screenshot-ui-capture-button .screenshot-ui-capture-button-circle:hover, .screenshot-ui-capture-button .screenshot-ui-capture-button-circle:focus {
 +      background-color: #dedede; }
 +  .screenshot-ui-capture-button:hover .screenshot-ui-capture-button-circle, .screenshot-ui-capture-button:focus .screenshot-ui-capture-button-circle {
 +    background-color: #cccccc; }
 +  .screenshot-ui-capture-button:active .screenshot-ui-capture-button-circle {
 +    background-color: gray; }
 +  .screenshot-ui-capture-button:cast .screenshot-ui-capture-button-circle {
 +    background-color: #c01c28; }
 +  .screenshot-ui-capture-button:cast:hover .screenshot-ui-capture-button-circle, .screenshot-ui-capture-button:cast:focus .screenshot-ui-capture-button-circle {
 +    background-color: #d61f2d; }
 +  .screenshot-ui-capture-button:cast:active .screenshot-ui-capture-button-circle {
 +    background-color: #a11722; }
 +
 +.screenshot-ui-shot-cast-container {
 +  background-color: rgba(255, 255, 255, 0.1);
 +  border-radius: 999px;
 +  padding: 3px;
 +  spacing: 3px; }
 +
 +.screenshot-ui-shot-cast-button {
 +  padding: 6px 12px;
 +  background-color: transparent;
 +  border-radius: 999px; }
 +  .screenshot-ui-shot-cast-button > StIcon {
 +    icon-size: 16px; }
 +  .screenshot-ui-shot-cast-button:hover, .screenshot-ui-shot-cast-button:focus {
 +    background-color: rgba(255, 255, 255, 0.2); }
 +  .screenshot-ui-shot-cast-button:active {
 +    background-color: rgba(255, 255, 255, 0.5); }
 +  .screenshot-ui-shot-cast-button:checked {
 +    background-color: #ffffff;
 +    color: #353535; }
 +  .screenshot-ui-shot-cast-button:insensitive {
 +    color: rgba(255, 255, 255, 0.5); }
 +
 +.screenshot-ui-area-indicator-shade {
 +  background-color: rgba(0, 0, 0, 0.3); }
 +
 +.screenshot-ui-area-selector .screenshot-ui-area-indicator-shade {
 +  background-color: rgba(0, 0, 0, 0.5); }
 +
 +.screenshot-ui-area-selector .screenshot-ui-area-indicator-selection {
 +  border: 2px white; }
 +
 +.screenshot-ui-area-selector-handle {
 +  border-radius: 999px;
 +  background-color: white;
 +  box-shadow: 0 1px 3px 2px rgba(0, 0, 0, 0.05);
 +  width: 24px;
 +  height: 24px; }
 +
 +.screenshot-ui-window-selector {
 +  background-color: #282828; }
 +  .screenshot-ui-window-selector .screenshot-ui-window-selector-window-container {
 +    margin: 100px; }
 +  .screenshot-ui-window-selector:primary-monitor .screenshot-ui-window-selector-window-container {
 +    margin-bottom: 200px; }
 +
 +.screenshot-ui-window-selector-window-border {
 +  transition-duration: 200ms;
 +  border-radius: 16px;
 +  border: 6px transparent; }
 +
 +.screenshot-ui-window-selector-check {
 +  transition-duration: 200ms;
 +  color: transparent;
 +  border-radius: 999px;
 +  border-width: 12px;
 +  icon-size: 24px; }
 +
 +.screenshot-ui-window-selector-window:hover .screenshot-ui-window-selector-window-border {
-   border-color: #1c71d8;
-   background-color: rgba(28, 113, 216, 0.2); }
++  border-color: st-darken(-st-accent-color, 15%); }
 +
 +.screenshot-ui-window-selector-window:checked .screenshot-ui-window-selector-window-border {
-   color: #ffffff;
-   background-color: #1c71d8; }
++  border-color: -st-accent-color;
++  background-color: st-transparentize(-st-accent-color, 0.8); }
 +
 +.screenshot-ui-window-selector-window:checked .screenshot-ui-window-selector-check {
-     border-color: #134e94; }
++  color: -st-accent-fg-color;
++  background-color: -st-accent-color; }
 +
 +.screenshot-ui-screen-selector {
 +  transition-duration: 200ms;
 +  background-color: rgba(0, 0, 0, 0.5); }
 +  .screenshot-ui-screen-selector:hover {
 +    background-color: rgba(0, 0, 0, 0.3); }
 +  .screenshot-ui-screen-selector:active {
 +    background-color: rgba(0, 0, 0, 0.7); }
 +  .screenshot-ui-screen-selector:checked {
 +    background-color: transparent;
 +    border: 2px white; }
 +
 +.screenshot-ui-tooltip {
 +  text-align: center;
 +  -y-offset: 24px; }
 +
 +/* Top Bar */
 +#panel {
 +  background-color: whitesmoke;
 +  font-weight: bold;
 +  height: 2.2em;
 +  transition-duration: 250ms; }
 +  #panel .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #282828;
 +    box-shadow: inset 0 0 0 100px transparent;
 +    -natural-hpadding: 12px;
 +    -minimum-hpadding: 6px; }
 +    #panel .panel-button:focus, #panel .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.17); }
 +    #panel .panel-button:active, #panel .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.28); }
 +      #panel .panel-button:active:hover, #panel .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.32); }
 +    #panel .panel-button .system-status-icon {
 +      icon-size: 1.091em;
 +      padding: 0 6px;
 +      margin: 0 4px; }
 +    #panel .panel-button .app-menu-icon {
 +      -st-icon-style: symbolic; }
 +    #panel .panel-button .panel-status-menu-box,
 +    #panel .panel-button .panel-status-indicators-box {
 +      spacing: 4px; }
 +      #panel .panel-button .panel-status-menu-box > .system-status-icon,
 +      #panel .panel-button .panel-status-indicators-box > .system-status-icon {
 +        padding: 0; }
 +    #panel .panel-button#panelActivities StBoxLayout {
 +      padding: 0 0.2045em;
 +      spacing: 5px; }
 +    #panel .panel-button#panelActivities .workspace-dot {
 +      border-radius: 999px;
 +      min-width: 0.5455em;
 +      min-height: 0.5455em;
 +      background-color: #282828; }
 +    #panel .panel-button.screen-recording-indicator StBoxLayout, #panel .panel-button.screen-sharing-indicator StBoxLayout {
 +      spacing: 0.409em; }
 +    #panel .panel-button.screen-recording-indicator StIcon, #panel .panel-button.screen-sharing-indicator StIcon {
 +      icon-size: 1.091em; }
 +    #panel .panel-button.screen-recording-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #c01c28; }
 +      #panel .panel-button.screen-recording-indicator:focus, #panel .panel-button.screen-recording-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #aa1923; }
 +      #panel .panel-button.screen-recording-indicator:active, #panel .panel-button.screen-recording-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #981620; }
 +        #panel .panel-button.screen-recording-indicator:active:hover, #panel .panel-button.screen-recording-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #8f151e; }
 +    #panel .panel-button.screen-sharing-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #e66100; }
 +      #panel .panel-button.screen-sharing-indicator:focus, #panel .panel-button.screen-sharing-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #cd5600; }
 +      #panel .panel-button.screen-sharing-indicator:active, #panel .panel-button.screen-sharing-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #b84e00; }
 +        #panel .panel-button.screen-sharing-indicator:active:hover, #panel .panel-button.screen-sharing-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #ae4900; }
 +    #panel .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #282828;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel .panel-button.clock-display:focus, #panel .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.17); }
 +      #panel .panel-button.clock-display:active, #panel .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.28); }
 +        #panel .panel-button.clock-display:active:hover, #panel .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.32); }
 +      #panel .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel .panel-button.clock-display:focus .clock, #panel .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.17); }
 +      #panel .panel-button.clock-display:active .clock, #panel .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.28); }
 +        #panel .panel-button.clock-display:active .clock:hover, #panel .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(40, 40, 40, 0.32); }
 +      #panel .panel-button.clock-display .messages-indicator {
 +        icon-size: 1.091em; }
 +  #panel:overview, #panel.unlock-screen, #panel.login-screen {
 +    background-color: transparent; }
 +    #panel:overview .panel-button.screen-recording-indicator, #panel.unlock-screen .panel-button.screen-recording-indicator, #panel.login-screen .panel-button.screen-recording-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #c01c28; }
 +      #panel:overview .panel-button.screen-recording-indicator:focus, #panel:overview .panel-button.screen-recording-indicator:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:focus, #panel.unlock-screen .panel-button.screen-recording-indicator:hover, #panel.login-screen .panel-button.screen-recording-indicator:focus, #panel.login-screen .panel-button.screen-recording-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #aa1923; }
 +      #panel:overview .panel-button.screen-recording-indicator:active, #panel:overview .panel-button.screen-recording-indicator:checked, #panel.unlock-screen .panel-button.screen-recording-indicator:active, #panel.unlock-screen .panel-button.screen-recording-indicator:checked, #panel.login-screen .panel-button.screen-recording-indicator:active, #panel.login-screen .panel-button.screen-recording-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #981620; }
 +        #panel:overview .panel-button.screen-recording-indicator:active:hover, #panel:overview .panel-button.screen-recording-indicator:checked:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:active:hover, #panel.unlock-screen .panel-button.screen-recording-indicator:checked:hover, #panel.login-screen .panel-button.screen-recording-indicator:active:hover, #panel.login-screen .panel-button.screen-recording-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #8f151e; }
 +    #panel:overview .panel-button.screen-sharing-indicator, #panel.unlock-screen .panel-button.screen-sharing-indicator, #panel.login-screen .panel-button.screen-sharing-indicator {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px #e66100; }
 +      #panel:overview .panel-button.screen-sharing-indicator:focus, #panel:overview .panel-button.screen-sharing-indicator:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:focus, #panel.unlock-screen .panel-button.screen-sharing-indicator:hover, #panel.login-screen .panel-button.screen-sharing-indicator:focus, #panel.login-screen .panel-button.screen-sharing-indicator:hover {
 +        box-shadow: inset 0 0 0 100px #cd5600; }
 +      #panel:overview .panel-button.screen-sharing-indicator:active, #panel:overview .panel-button.screen-sharing-indicator:checked, #panel.unlock-screen .panel-button.screen-sharing-indicator:active, #panel.unlock-screen .panel-button.screen-sharing-indicator:checked, #panel.login-screen .panel-button.screen-sharing-indicator:active, #panel.login-screen .panel-button.screen-sharing-indicator:checked {
 +        box-shadow: inset 0 0 0 100px #b84e00; }
 +        #panel:overview .panel-button.screen-sharing-indicator:active:hover, #panel:overview .panel-button.screen-sharing-indicator:checked:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:active:hover, #panel.unlock-screen .panel-button.screen-sharing-indicator:checked:hover, #panel.login-screen .panel-button.screen-sharing-indicator:active:hover, #panel.login-screen .panel-button.screen-sharing-indicator:checked:hover {
 +          box-shadow: inset 0 0 0 100px #ae4900; }
 +  #panel.unlock-screen .panel-button, #panel.login-screen .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: #ffffff;
 +    box-shadow: inset 0 0 0 100px transparent; }
 +    #panel.unlock-screen .panel-button:focus, #panel.unlock-screen .panel-button:hover, #panel.login-screen .panel-button:focus, #panel.login-screen .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +    #panel.unlock-screen .panel-button:active, #panel.unlock-screen .panel-button:checked, #panel.login-screen .panel-button:active, #panel.login-screen .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +      #panel.unlock-screen .panel-button:active:hover, #panel.unlock-screen .panel-button:checked:hover, #panel.login-screen .panel-button:active:hover, #panel.login-screen .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +    #panel.unlock-screen .panel-button.clock-display, #panel.login-screen .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: #ffffff;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel.unlock-screen .panel-button.clock-display:focus, #panel.unlock-screen .panel-button.clock-display:hover, #panel.login-screen .panel-button.clock-display:focus, #panel.login-screen .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel.unlock-screen .panel-button.clock-display:active, #panel.unlock-screen .panel-button.clock-display:checked, #panel.login-screen .panel-button.clock-display:active, #panel.login-screen .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel.unlock-screen .panel-button.clock-display:active:hover, #panel.unlock-screen .panel-button.clock-display:checked:hover, #panel.login-screen .panel-button.clock-display:active:hover, #panel.login-screen .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +      #panel.unlock-screen .panel-button.clock-display .clock, #panel.login-screen .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel.unlock-screen .panel-button.clock-display:focus .clock, #panel.unlock-screen .panel-button.clock-display:hover .clock, #panel.login-screen .panel-button.clock-display:focus .clock, #panel.login-screen .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17); }
 +      #panel.unlock-screen .panel-button.clock-display:active .clock, #panel.unlock-screen .panel-button.clock-display:checked .clock, #panel.login-screen .panel-button.clock-display:active .clock, #panel.login-screen .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28); }
 +        #panel.unlock-screen .panel-button.clock-display:active .clock:hover, #panel.unlock-screen .panel-button.clock-display:checked .clock:hover, #panel.login-screen .panel-button.clock-display:active .clock:hover, #panel.login-screen .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32); }
 +  #panel:overview .panel-button {
 +    transition-duration: 150ms;
 +    border: 3px solid transparent;
 +    background-color: transparent;
 +    border-radius: 999px;
 +    font-weight: bold;
 +    color: whitesmoke;
 +    box-shadow: inset 0 0 0 100px transparent; }
 +    #panel:overview .panel-button:focus, #panel:overview .panel-button:hover {
 +      box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.17); }
 +    #panel:overview .panel-button:active, #panel:overview .panel-button:checked {
 +      box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.28); }
 +      #panel:overview .panel-button:active:hover, #panel:overview .panel-button:checked:hover {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.32); }
 +    #panel:overview .panel-button#panelActivities .workspace-dot {
 +      background-color: whitesmoke; }
 +    #panel:overview .panel-button.clock-display {
 +      transition-duration: 150ms;
 +      border: 3px solid transparent;
 +      background-color: transparent;
 +      border-radius: 999px;
 +      font-weight: bold;
 +      color: whitesmoke;
 +      box-shadow: inset 0 0 0 100px transparent;
 +      background: none !important;
 +      box-shadow: none !important;
 +      border: none !important; }
 +      #panel:overview .panel-button.clock-display:focus, #panel:overview .panel-button.clock-display:hover {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.17); }
 +      #panel:overview .panel-button.clock-display:active, #panel:overview .panel-button.clock-display:checked {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.28); }
 +        #panel:overview .panel-button.clock-display:active:hover, #panel:overview .panel-button.clock-display:checked:hover {
 +          box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.32); }
 +      #panel:overview .panel-button.clock-display .clock {
 +        transition-duration: 150ms;
 +        border: 3px solid transparent;
 +        border-radius: 999px; }
 +      #panel:overview .panel-button.clock-display:focus .clock, #panel:overview .panel-button.clock-display:hover .clock {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.17); }
 +      #panel:overview .panel-button.clock-display:active .clock, #panel:overview .panel-button.clock-display:checked .clock {
 +        box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.28); }
 +        #panel:overview .panel-button.clock-display:active .clock:hover, #panel:overview .panel-button.clock-display:checked .clock:hover {
 +          box-shadow: inset 0 0 0 100px rgba(245, 245, 245, 0.32); }
 +  #panel .panel-status-indicators-box,
 +  #panel .panel-status-menu-box {
 +    spacing: 2px; }
 +  #panel .power-status.panel-status-indicators-box {
 +    spacing: 0; }
 +  #panel .privacy-indicator {
 +    color: #e66100; }
 +
 +#appMenu {
 +  spacing: 0.409em; }
 +  #appMenu .label-shadow {
 +    color: transparent; }
 +
 +#appMenu .panel-status-menu-box {
 +  padding: 0 0.409em;
 +  spacing: 0.409em; }
 +
 +.clock-display-box {
 +  spacing: 2px; }
 +  .clock-display-box .clock {
 +    padding-left: 0.818em;
 +    padding-right: 0.818em; }
 +
 +/* Activities Ripple */
 +.ripple-box {
 +  background-color: rgba(255, 255, 255, 0.2);
 +  box-shadow: 0 0 2px 2px rgba(255, 255, 255, 0.2);
 +  width: 52px;
 +  height: 52px;
 +  border-radius: 0 0 52px 0; }
 +  .ripple-box:rtl {
 +    border-radius: 0 0 0 52px; }
 +
 +.quick-settings {
 +  padding: 18px;
 +  border-radius: 36px; }
 +  .quick-settings .icon-button, .quick-settings .login-dialog-button.cancel-button, .quick-settings .login-dialog-button.switch-user-button, .quick-settings .login-dialog-button.login-dialog-session-list-button, .quick-settings .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .quick-settings .pager-button, .quick-settings .message .message-header .message-expand-button, .message .message-header .quick-settings .message-expand-button,
 +  .quick-settings .message .message-header .message-close-button,
 +  .message .message-header .quick-settings .message-close-button, .quick-settings .screenshot-ui-show-pointer-button, .quick-settings .button {
 +    padding: 10.5px; }
 +
 +.quick-settings-grid {
 +  spacing-rows: 12px;
 +  spacing-columns: 12px; }
 +
 +.quick-toggle, .quick-menu-toggle {
 +  border-radius: 999px;
 +  min-width: 12em;
 +  max-width: 12em;
 +  min-height: 3.273em;
 +  border: none; }
 +
 +.quick-toggle {
 +  background-color: none;
 +  /* Move padding into the box; this is to allow menu arrows
 +     to extend to the border */ }
 +  .quick-toggle > StBoxLayout {
 +    spacing: 9px; }
 +  .quick-toggle.button {
 +    padding: 0; }
 +  .quick-toggle > StBoxLayout {
 +    padding: 0 12px; }
 +  .quick-toggle:ltr > StBoxLayout {
 +    padding-left: 15px; }
 +  .quick-toggle:rtl > StBoxLayout {
 +    padding-right: 15px; }
 +  .quick-toggle .quick-toggle-title {
 +    font-weight: bold; }
 +  .quick-toggle StBoxLayout > .quick-toggle-subtitle {
 +    font-weight: normal; }
 +  .quick-toggle .quick-toggle-icon {
 +    icon-size: 1.091em; }
 +
 +.quick-menu-toggle .quick-toggle {
 +  min-width: auto;
 +  max-width: auto; }
 +  .quick-menu-toggle .quick-toggle:ltr {
 +    border-radius: 999px 0 0 999px; }
 +  .quick-menu-toggle .quick-toggle:ltr > StBoxLayout {
 +    padding-right: 0.6135em; }
 +  .quick-menu-toggle .quick-toggle:rtl {
 +    border-radius: 0 999px 999px 0; }
 +  .quick-menu-toggle .quick-toggle:rtr > StBoxLayout {
 +    padding-left: 0.6135em; }
 +  .quick-menu-toggle .quick-toggle:ltr:last-child {
 +    border-radius: 999px; }
 +  .quick-menu-toggle .quick-toggle:rtl:last-child {
 +    border-radius: 999px; }
 +
 +.quick-menu-toggle .quick-toggle-arrow {
 +  padding: 0.409em 0.71575em;
 +  border-width: 0;
 +  border-color: rgba(40, 40, 40, 0.25); }
 +  .quick-menu-toggle .quick-toggle-arrow:checked {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #d2d7dc; }
++    border-color: st-darken(-st-accent-color, 15%); }
 +  .quick-menu-toggle .quick-toggle-arrow:ltr {
 +    border-radius: 0 999px 999px 0;
 +    border-left-width: 1px; }
 +  .quick-menu-toggle .quick-toggle-arrow:rtl {
 +    border-radius: 999px 0 0 999px;
 +    border-right-width: 1px; }
 +
 +.quick-slider > StBoxLayout {
 +  spacing: 6px; }
 +
 +.quick-slider .icon-button, .quick-slider .login-dialog-button.cancel-button, .quick-slider .login-dialog-button.switch-user-button, .quick-slider .login-dialog-button.login-dialog-session-list-button, .quick-slider .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .quick-slider .pager-button, .quick-slider .message .message-header .message-expand-button, .message .message-header .quick-slider .message-expand-button,
 +.quick-slider .message .message-header .message-close-button,
 +.message .message-header .quick-slider .message-close-button, .quick-slider .screenshot-ui-show-pointer-button {
 +  padding: 6px; }
 +
 +.quick-slider .slider-bin {
 +  padding: 6px;
 +  border-radius: 999px; }
 +  .quick-slider .slider-bin:focus {
 +    color: #282828;
-       background-color: #c9cdd2; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#282828, whitesmoke, 12%), 5%); }
 +    .quick-slider .slider-bin:focus:hover {
-     background-color: gainsboro; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, whitesmoke, 12%), 4%), 5%); }
 +
 +.quick-toggle-menu {
 +  border-radius: 24px;
 +  margin: 12px 18px 0; }
 +  .quick-toggle-menu:insensitive {
 +    color: #282828;
-         background-color: #1c71d8;
-         color: #ffffff; }
++    background-color: st-mix(#282828, whitesmoke, 12%); }
 +  .quick-toggle-menu .popup-menu-item > StIcon {
 +    -st-icon-style: symbolic;
 +    icon-size: 1.091em; }
 +  .quick-toggle-menu .header {
 +    spacing-rows: 3px;
 +    spacing-columns: 12px;
 +    padding-bottom: 12px; }
 +    .quick-toggle-menu .header .icon {
 +      icon-size: 1.6365em;
 +      border-radius: 999px;
 +      padding: 9px;
 +      background-color: rgba(40, 40, 40, 0.2); }
 +      .quick-toggle-menu .header .icon.active {
-     background-color: gainsboro;
++        background-color: -st-accent-color;
++        color: -st-accent-fg-color; }
 +
 +.quick-settings-system-item > StBoxLayout {
 +  spacing: 12px; }
 +
 +.quick-settings-system-item .power-item {
 +  min-height: 0;
 +  min-width: 0; }
 +  .quick-settings-system-item .power-item:insensitive {
 +    color: #282828;
- .controls-manager, .secondary-monitor-workspaces {
++    background-color: st-mix(#282828, whitesmoke, 12%);
 +    background-color: transparent; }
 +
 +.nm-network-item .wireless-secure-icon {
 +  icon-size: 0.5455em; }
 +
 +.bt-device-item .popup-menu-icon {
 +  -st-icon-style: symbolic; }
 +
 +.bt-menu-placeholder.popup-menu-item {
 +  text-align: center;
 +  padding: 2em 4em; }
 +
 +.device-subtitle {
 +  color: rgba(40, 40, 40, 0.5); }
 +
 +.keyboard-brightness-level {
 +  spacing: 6px; }
 +
 +.background-apps-quick-toggle {
 +  min-height: 2.728em;
 +  background-color: transparent; }
 +  .background-apps-quick-toggle StIcon {
 +    icon-size: 1.091em !important; }
 +
 +.background-app-item .popup-menu-icon {
 +  icon-size: 32px !important;
 +  -st-icon-style: regular !important; }
 +
 +.background-app-item .icon-button, .background-app-item .login-dialog-button.cancel-button, .background-app-item .login-dialog-button.switch-user-button, .background-app-item .login-dialog-button.login-dialog-session-list-button, .background-app-item .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .background-app-item .pager-button, .background-app-item .message .message-header .message-expand-button, .message .message-header .background-app-item .message-expand-button,
 +.background-app-item .message .message-header .message-close-button,
 +.message .message-header .background-app-item .message-close-button, .background-app-item .screenshot-ui-show-pointer-button {
 +  padding: 6px;
 +  background-color: rgba(40, 40, 40, 0.13); }
 +  .background-app-item .icon-button:hover, .background-app-item .login-dialog-button.cancel-button:hover, .background-app-item .login-dialog-button.switch-user-button:hover, .background-app-item .login-dialog-button.login-dialog-session-list-button:hover, .background-app-item .calendar .calendar-month-header .pager-button:hover, .calendar .calendar-month-header .background-app-item .pager-button:hover, .background-app-item .message .message-header .message-expand-button:hover, .message .message-header .background-app-item .message-expand-button:hover,
 +  .background-app-item .message .message-header .message-close-button:hover,
 +  .message .message-header .background-app-item .message-close-button:hover, .background-app-item .screenshot-ui-show-pointer-button:hover {
 +    background-color: rgba(40, 40, 40, 0.22); }
 +  .background-app-item .icon-button:active, .background-app-item .login-dialog-button.cancel-button:active, .background-app-item .login-dialog-button.switch-user-button:active, .background-app-item .login-dialog-button.login-dialog-session-list-button:active, .background-app-item .calendar .calendar-month-header .pager-button:active, .calendar .calendar-month-header .background-app-item .pager-button:active, .background-app-item .message .message-header .message-expand-button:active, .message .message-header .background-app-item .message-expand-button:active,
 +  .background-app-item .message .message-header .message-close-button:active,
 +  .message .message-header .background-app-item .message-close-button:active, .background-app-item .screenshot-ui-show-pointer-button:active {
 +    background-color: rgba(40, 40, 40, 0.31); }
 +
 +.background-app-item .spinner {
 +  padding: 6px; }
 +
 +.background-app-item.popup-inactive-menu-item {
 +  color: #282828; }
 +
 +/* OVERVIEW */
- .overview-controls {
-   padding-bottom: 32px; }
- 
++.secondary-monitor-workspaces {
 +  spacing: 12px; }
 +
 +#overviewGroup {
 +  background-color: #282828; }
 +
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(52, 75, 103, 0.2875); }
 +/* Window Picker */
 +.window-picker {
 +  spacing: 6px; }
 +
 +.window-close, .screenshot-ui-close-button {
 +  background-color: rgba(71, 71, 71, 0.98);
 +  color: whitesmoke;
 +  border-radius: 999px;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.05);
 +  padding: 3px;
 +  height: 32px;
 +  width: 32px;
 +  transition-duration: 100ms;
 +  border: 2px solid transparent; }
 +  .window-close StIcon, .screenshot-ui-close-button StIcon {
 +    icon-size: 24px; }
 +  .window-close:hover, .screenshot-ui-close-button:hover {
 +    background-color: rgba(88, 88, 88, 0.98); }
 +  .window-close:active, .screenshot-ui-close-button:active {
 +    background-color: rgba(104, 104, 104, 0.98); }
 +
 +.workspace-background {
 +  border-radius: 30px;
 +  background-color: rgba(3, 2, 1, 0);
 +  box-shadow: 0 4px 16px 4px rgba(0, 0, 0, 0.05); }
 +
 +.search-entry {
 +  border-radius: 999px;
 +  margin-top: 12px;
 +  margin-bottom: 6px;
 +  width: 24em; }
 +  .search-entry .search-entry-icon {
 +    icon-size: 1.091em;
 +    margin-top: 2px;
 +    padding: 0 4px; }
 +
 +/* Search */
 +#searchResults {
 +  margin: 0 4px; }
 +
 +#searchResultsContent {
 +  max-width: 1044px; }
 +
 +.search-section {
 +  spacing: 18px; }
 +  .search-section .search-section-separator {
 +    height: 8px;
 +    background-color: transparent; }
 +
 +.search-section-content {
 +  background-color: #3d3d3d;
 +  color: whitesmoke;
 +  border-radius: 24px;
 +  padding: 12px;
 +  margin: 0 12px;
 +  border: 2px solid transparent; }
 +
 +.list-search-result, .search-provider-icon {
 +  color: whitesmoke;
 +  background-color: #3d3d3d;
 +  border-radius: 13.2px; }
 +  .list-search-result:focus, .search-provider-icon:focus {
 +    color: whitesmoke;
-       background-color: #4c5156; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(61, 61, 61, 0.25), 5%); }
 +    .list-search-result:focus:hover, .search-provider-icon:focus:hover {
-     background-color: #4f4f4f; }
++      background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 7%), 5%); }
 +  .list-search-result:hover, .search-provider-icon:hover {
 +    color: whitesmoke;
-     background-color: #545454; }
++    background-color: st-lighten(#3d3d3d, 7%); }
 +  .list-search-result:active, .search-provider-icon:active {
 +    color: whitesmoke;
-       background-color: #666666; }
++    background-color: st-lighten(#3d3d3d, 9%); }
 +    .list-search-result:active:hover, .search-provider-icon:active:hover {
-       background-color: #51555b; }
++      background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +    .list-search-result:active:focus, .search-provider-icon:active:focus {
-     background-color: #515151; }
++      background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +  .list-search-result:highlighted, .search-provider-icon:highlighted, .list-search-result:selected, .search-provider-icon:selected, .list-search-result:checked, .search-provider-icon:checked {
 +    color: whitesmoke;
-       background-color: #636363; }
++    background-color: st-lighten(#3d3d3d, 8%); }
 +    .list-search-result:highlighted:hover, .search-provider-icon:highlighted:hover, .list-search-result:selected:hover, .search-provider-icon:selected:hover, .list-search-result:checked:hover, .search-provider-icon:checked:hover {
-       background-color: #686868; }
++      background-color: st-lighten(st-lighten(#3d3d3d, 8%), 7%); }
 +    .list-search-result:highlighted:active, .search-provider-icon:highlighted:active, .list-search-result:selected:active, .search-provider-icon:selected:active, .list-search-result:checked:active, .search-provider-icon:checked:active {
-     color: rgba(245, 245, 245, 0.4);
++      background-color: st-lighten(st-lighten(#3d3d3d, 8%), 9%); }
 +  .list-search-result:insensitive, .search-provider-icon:insensitive {
-     background-color: rgba(28, 113, 216, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.8); }
++    color: st-transparentize(whitesmoke, 0.6);
 +    background-color: #3d3d3d; }
 +  .list-search-result:drop, .search-provider-icon:drop {
-   margin-top: 12px; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.search-statustext {
 +  color: rgba(245, 245, 245, 0.8); }
 +
 +.grid-search-results {
 +  spacing: 30px; }
 +
 +.search-provider-icon:ltr {
 +  margin-right: 4px; }
 +
 +.search-provider-icon:rtl {
 +  margin-left: 4px; }
 +
 +.search-provider-icon .list-search-provider-content {
 +  spacing: 12px; }
 +  .search-provider-icon .list-search-provider-content .list-search-provider-details {
 +    width: 120px;
 +    color: whitesmoke; }
 +
 +.list-search-results {
 +  spacing: 6px; }
 +
 +.list-search-result .list-search-result-content {
 +  spacing: 6px; }
 +
 +.list-search-result .list-search-result-title {
 +  spacing: 12px; }
 +
 +.list-search-result .list-search-result-description {
 +  color: #959595; }
 +
 +/* Dash */
 +#dash {
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-       background-color: rgba(52, 75, 103, 0.2875); }
++  padding-left: 6px;
++  padding-right: 6px; }
 +  #dash .dash-background {
 +    background-color: #3d3d3d;
 +    border-radius: 28px;
 +    padding-top: 12px;
 +    padding-bottom: 12px;
 +    padding-left: 10px;
 +    padding-right: 10px; }
 +  #dash .dash-item-container .placeholder {
 +    background-image: none;
 +    background-size: contain;
 +    height: 32px; }
 +  #dash .dash-item-container .empty-dash-drop-target {
 +    width: 32px;
 +    height: 32px; }
 +  #dash .dash-item-container .show-apps,
 +  #dash .dash-item-container .overview-tile,
 +  #dash .dash-item-container .grid-search-result {
 +    margin: 0 2px;
 +    padding-bottom: 12px; }
 +    #dash .dash-item-container .show-apps .overview-icon,
 +    #dash .dash-item-container .overview-tile .overview-icon,
 +    #dash .dash-item-container .grid-search-result .overview-icon {
 +      color: whitesmoke;
 +      background-color: #3d3d3d; }
 +    #dash .dash-item-container .show-apps:focus .overview-icon,
 +    #dash .dash-item-container .overview-tile:focus .overview-icon,
 +    #dash .dash-item-container .grid-search-result:focus .overview-icon {
 +      color: whitesmoke;
-         background-color: #4c5156; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, rgba(61, 61, 61, 0.25), 5%); }
 +      #dash .dash-item-container .show-apps:focus .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:focus .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:focus .overview-icon:hover {
-       background-color: #4f4f4f; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 7%), 5%); }
 +    #dash .dash-item-container .show-apps:hover .overview-icon,
 +    #dash .dash-item-container .overview-tile:hover .overview-icon,
 +    #dash .dash-item-container .grid-search-result:hover .overview-icon {
 +      color: whitesmoke;
-       background-color: #545454; }
++      background-color: st-lighten(#3d3d3d, 7%); }
 +    #dash .dash-item-container .show-apps:active .overview-icon,
 +    #dash .dash-item-container .overview-tile:active .overview-icon,
 +    #dash .dash-item-container .grid-search-result:active .overview-icon {
 +      color: whitesmoke;
-         background-color: #666666; }
++      background-color: st-lighten(#3d3d3d, 9%); }
 +      #dash .dash-item-container .show-apps:active .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:active .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:active .overview-icon:hover {
-         background-color: #51555b; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +      #dash .dash-item-container .show-apps:active .overview-icon:focus,
 +      #dash .dash-item-container .overview-tile:active .overview-icon:focus,
 +      #dash .dash-item-container .grid-search-result:active .overview-icon:focus {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +    #dash .dash-item-container .show-apps:checked .overview-icon,
 +    #dash .dash-item-container .overview-tile:checked .overview-icon,
 +    #dash .dash-item-container .grid-search-result:checked .overview-icon {
 +      color: whitesmoke;
-         background-color: #636363; }
++      background-color: st-lighten(#3d3d3d, 8%); }
 +      #dash .dash-item-container .show-apps:checked .overview-icon:hover,
 +      #dash .dash-item-container .overview-tile:checked .overview-icon:hover,
 +      #dash .dash-item-container .grid-search-result:checked .overview-icon:hover {
-         background-color: #686868; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 7%); }
 +      #dash .dash-item-container .show-apps:checked .overview-icon:active,
 +      #dash .dash-item-container .overview-tile:checked .overview-icon:active,
 +      #dash .dash-item-container .grid-search-result:checked .overview-icon:active {
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(37, 60, 87, 0.2875); }
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 9%); }
 +  #dash .dash-item-container .app-grid-running-dot {
 +    offset-y: -12px; }
 +  #dash .dash-separator {
 +    width: 1px;
 +    margin-left: 4px;
 +    margin-right: 4px;
 +    background-color: rgba(245, 245, 245, 0.1); }
 +  #dash .dash-separator,
 +  #dash .dash-background {
 +    margin-bottom: 12px; }
 +
 +.dash-label {
 +  -y-offset: 8px; }
 +
 +/* App Grid */
 +.icon-grid {
 +  row-spacing: 12px;
 +  column-spacing: 12px;
 +  max-row-spacing: 36px;
 +  max-column-spacing: 36px;
 +  page-padding-top: 24px;
 +  page-padding-bottom: 24px;
 +  page-padding-left: 18px;
 +  page-padding-right: 18px; }
 +
 +/* App Icons */
 +.overview-tile, .grid-search-result {
 +  color: whitesmoke;
 +  background-color: #282828;
 +  border-radius: 24px;
 +  padding: 12px; }
 +  .overview-tile:focus, .grid-search-result:focus {
 +    color: whitesmoke;
-       background-color: #383d42; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.25), 5%); }
 +    .overview-tile:focus:hover, .grid-search-result:focus:hover {
-     background-color: #3a3a3a; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 7%), 5%); }
 +  .overview-tile:hover, .grid-search-result:hover {
 +    color: whitesmoke;
-     background-color: #3f3f3f; }
++    background-color: st-lighten(#282828, 7%); }
 +  .overview-tile:active, .grid-search-result:active {
 +    color: whitesmoke;
-       background-color: #515151; }
++    background-color: st-lighten(#282828, 9%); }
 +    .overview-tile:active:hover, .grid-search-result:active:hover {
-       background-color: #3d4147; }
++      background-color: st-lighten(st-lighten(#282828, 9%), 7%); }
 +    .overview-tile:active:focus, .grid-search-result:active:focus {
-     background-color: #3c3c3c; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 9%), 5%); }
 +  .overview-tile:highlighted, .grid-search-result:highlighted, .overview-tile:selected, .grid-search-result:selected, .overview-tile:checked, .grid-search-result:checked {
 +    color: whitesmoke;
-       background-color: #4e4e4e; }
++    background-color: st-lighten(#282828, 8%); }
 +    .overview-tile:highlighted:hover, .grid-search-result:highlighted:hover, .overview-tile:selected:hover, .grid-search-result:selected:hover, .overview-tile:checked:hover, .grid-search-result:checked:hover {
-       background-color: #535353; }
++      background-color: st-lighten(st-lighten(#282828, 8%), 7%); }
 +    .overview-tile:highlighted:active, .grid-search-result:highlighted:active, .overview-tile:selected:active, .grid-search-result:selected:active, .overview-tile:checked:active, .grid-search-result:checked:active {
-     color: rgba(245, 245, 245, 0.4);
++      background-color: st-lighten(st-lighten(#282828, 8%), 9%); }
 +  .overview-tile:insensitive, .grid-search-result:insensitive {
-     background-color: rgba(28, 113, 216, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.8); }
++    color: st-transparentize(whitesmoke, 0.6);
 +    background-color: #282828; }
 +  .overview-tile:drop, .grid-search-result:drop {
-   background-color: #414141; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +  .overview-tile .overview-icon.overview-icon-with-label > StBoxLayout, .grid-search-result .overview-icon.overview-icon-with-label > StBoxLayout {
 +    spacing: 6px; }
 +
 +.app-folder {
 +  color: whitesmoke;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #3f4349; }
++  background-color: st-mix(whitesmoke, #282828, 12%); }
 +  .app-folder:focus {
 +    color: whitesmoke;
-       background-color: #494d52; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(whitesmoke, #282828, 12%), 5%); }
 +    .app-folder:focus:hover {
-     background-color: #4b4b4b; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 12%), 4%), 5%); }
 +  .app-folder:hover {
 +    color: whitesmoke;
-     background-color: #585858; }
++    background-color: st-lighten(st-mix(whitesmoke, #282828, 12%), 4%); }
 +  .app-folder:active {
 +    color: whitesmoke;
-       background-color: #626262; }
++    background-color: st-lighten(st-mix(whitesmoke, #282828, 12%), 9%); }
 +    .app-folder:active:hover {
-       background-color: #55595e; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 12%), 9%), 4%); }
 +    .app-folder:active:focus {
-     background-color: #555555; }
++      background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 12%), 9%), 5%); }
 +  .app-folder:highlighted, .app-folder:selected, .app-folder:checked {
 +    color: whitesmoke;
-       background-color: #606060; }
++    background-color: st-lighten(st-mix(whitesmoke, #282828, 12%), 8%); }
 +    .app-folder:highlighted:hover, .app-folder:selected:hover, .app-folder:checked:hover {
-       background-color: #6c6c6c; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 12%), 8%), 4%); }
 +    .app-folder:highlighted:active, .app-folder:selected:active, .app-folder:checked:active {
-     color: rgba(245, 245, 245, 0.4);
-     background-color: #393939; }
++      background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 12%), 8%), 9%); }
 +  .app-folder:insensitive {
-     background-color: rgba(28, 113, 216, 0.2);
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.8); }
++    color: st-transparentize(whitesmoke, 0.6);
++    background-color: st-darken(st-mix(whitesmoke, #282828, 12%), 3%); }
 +  .app-folder:drop {
-     background-color: #535353; }
++    background-color: st-transparentize(-st-accent-color, 0.8);
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.app-grid-running-dot {
 +  height: 5px;
 +  width: 5px;
 +  border-radius: 5px;
 +  background-color: whitesmoke;
 +  offset-y: 6px; }
 +
 +.app-folder-dialog-container {
 +  padding-top: 2.2em; }
 +
 +.app-folder-dialog {
 +  width: 720px;
 +  height: 720px;
 +  border-radius: 64px;
 +  background-color: #3d3d3d;
 +  color: whitesmoke;
 +  padding: 0 1px;
 +  box-shadow: inset 0 0 0 1px rgba(245, 245, 245, 0.1); }
 +  .app-folder-dialog .folder-name-container {
 +    padding: 24px 36px;
 +    padding-bottom: 0; }
 +    .app-folder-dialog .folder-name-container .folder-name-entry {
 +      width: 12em; }
 +  .app-folder-dialog .icon-button, .app-folder-dialog .login-dialog-button.cancel-button, .app-folder-dialog .login-dialog-button.switch-user-button, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button, .app-folder-dialog .calendar .calendar-month-header .pager-button, .calendar .calendar-month-header .app-folder-dialog .pager-button, .app-folder-dialog .message .message-header .message-expand-button, .message .message-header .app-folder-dialog .message-expand-button,
 +  .app-folder-dialog .message .message-header .message-close-button,
 +  .message .message-header .app-folder-dialog .message-close-button, .app-folder-dialog .screenshot-ui-show-pointer-button {
 +    color: whitesmoke;
-       background-color: #5d5d5d; }
++    background-color: st-mix(whitesmoke, #3d3d3d, 12%); }
 +    .app-folder-dialog .icon-button:hover, .app-folder-dialog .login-dialog-button.cancel-button:hover, .app-folder-dialog .login-dialog-button.switch-user-button:hover, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:hover, .app-folder-dialog .calendar .calendar-month-header .pager-button:hover, .calendar .calendar-month-header .app-folder-dialog .pager-button:hover, .app-folder-dialog .message .message-header .message-expand-button:hover, .message .message-header .app-folder-dialog .message-expand-button:hover,
 +    .app-folder-dialog .message .message-header .message-close-button:hover,
 +    .message .message-header .app-folder-dialog .message-close-button:hover, .app-folder-dialog .screenshot-ui-show-pointer-button:hover {
 +      color: whitesmoke;
-       background-color: #6a6a6a; }
++      background-color: st-lighten(st-mix(whitesmoke, #3d3d3d, 12%), 4%); }
 +    .app-folder-dialog .icon-button:active, .app-folder-dialog .login-dialog-button.cancel-button:active, .app-folder-dialog .login-dialog-button.switch-user-button:active, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active, .app-folder-dialog .calendar .calendar-month-header .pager-button:active, .calendar .calendar-month-header .app-folder-dialog .pager-button:active, .app-folder-dialog .message .message-header .message-expand-button:active, .message .message-header .app-folder-dialog .message-expand-button:active,
 +    .app-folder-dialog .message .message-header .message-close-button:active,
 +    .message .message-header .app-folder-dialog .message-close-button:active, .app-folder-dialog .screenshot-ui-show-pointer-button:active {
 +      color: whitesmoke;
-         background-color: #747474; }
++      background-color: st-lighten(st-mix(whitesmoke, #3d3d3d, 12%), 9%); }
 +      .app-folder-dialog .icon-button:active:hover, .app-folder-dialog .login-dialog-button.cancel-button:active:hover, .app-folder-dialog .login-dialog-button.switch-user-button:active:hover, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active:hover, .app-folder-dialog .calendar .calendar-month-header .pager-button:active:hover, .calendar .calendar-month-header .app-folder-dialog .pager-button:active:hover, .app-folder-dialog .message .message-header .message-expand-button:active:hover, .message .message-header .app-folder-dialog .message-expand-button:active:hover,
 +      .app-folder-dialog .message .message-header .message-close-button:active:hover,
 +      .message .message-header .app-folder-dialog .message-close-button:active:hover, .app-folder-dialog .screenshot-ui-show-pointer-button:active:hover {
-         background-color: #666a6f; }
++        background-color: st-lighten(st-lighten(st-mix(whitesmoke, #3d3d3d, 12%), 9%), 4%); }
 +      .app-folder-dialog .icon-button:active:focus, .app-folder-dialog .login-dialog-button.cancel-button:active:focus, .app-folder-dialog .login-dialog-button.switch-user-button:active:focus, .app-folder-dialog .login-dialog-button.login-dialog-session-list-button:active:focus, .app-folder-dialog .calendar .calendar-month-header .pager-button:active:focus, .calendar .calendar-month-header .app-folder-dialog .pager-button:active:focus, .app-folder-dialog .message .message-header .message-expand-button:active:focus, .message .message-header .app-folder-dialog .message-expand-button:active:focus,
 +      .app-folder-dialog .message .message-header .message-close-button:active:focus,
 +      .message .message-header .app-folder-dialog .message-close-button:active:focus, .app-folder-dialog .screenshot-ui-show-pointer-button:active:focus {
-       background-color: #4f4f4f; }
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #3d3d3d, 12%), 9%), 5%); }
 +  .app-folder-dialog .page-indicators {
 +    margin-bottom: 24px; }
 +  .app-folder-dialog .page-navigation-arrow {
 +    color: whitesmoke;
 +    background-color: #3d3d3d; }
 +    .app-folder-dialog .page-navigation-arrow:hover {
 +      color: whitesmoke;
-       background-color: #545454; }
++      background-color: st-lighten(#3d3d3d, 7%); }
 +    .app-folder-dialog .page-navigation-arrow:active {
 +      color: whitesmoke;
-         background-color: #666666; }
++      background-color: st-lighten(#3d3d3d, 9%); }
 +      .app-folder-dialog .page-navigation-arrow:active:hover {
-         background-color: #51555b; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +      .app-folder-dialog .page-navigation-arrow:active:focus {
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-       background-color: rgba(52, 75, 103, 0.2875); }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +  .app-folder-dialog .overview-tile, .app-folder-dialog .grid-search-result {
 +    color: whitesmoke;
 +    background-color: #3d3d3d; }
 +    .app-folder-dialog .overview-tile:focus, .app-folder-dialog .grid-search-result:focus {
 +      color: whitesmoke;
-         background-color: #4c5156; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, rgba(61, 61, 61, 0.25), 5%); }
 +      .app-folder-dialog .overview-tile:focus:hover, .app-folder-dialog .grid-search-result:focus:hover {
-       background-color: #4f4f4f; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 7%), 5%); }
 +    .app-folder-dialog .overview-tile:hover, .app-folder-dialog .grid-search-result:hover {
 +      color: whitesmoke;
-       background-color: #545454; }
++      background-color: st-lighten(#3d3d3d, 7%); }
 +    .app-folder-dialog .overview-tile:active, .app-folder-dialog .grid-search-result:active {
 +      color: whitesmoke;
-         background-color: #666666; }
++      background-color: st-lighten(#3d3d3d, 9%); }
 +      .app-folder-dialog .overview-tile:active:hover, .app-folder-dialog .grid-search-result:active:hover {
-         background-color: #51555b; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 9%), 7%); }
 +      .app-folder-dialog .overview-tile:active:focus, .app-folder-dialog .grid-search-result:active:focus {
-       background-color: #515151; }
++        background-color: st-mix(-st-accent-color, st-lighten(#3d3d3d, 9%), 5%); }
 +    .app-folder-dialog .overview-tile:highlighted, .app-folder-dialog .grid-search-result:highlighted, .app-folder-dialog .overview-tile:selected, .app-folder-dialog .grid-search-result:selected, .app-folder-dialog .overview-tile:checked, .app-folder-dialog .grid-search-result:checked {
 +      color: whitesmoke;
-         background-color: #636363; }
++      background-color: st-lighten(#3d3d3d, 8%); }
 +      .app-folder-dialog .overview-tile:highlighted:hover, .app-folder-dialog .grid-search-result:highlighted:hover, .app-folder-dialog .overview-tile:selected:hover, .app-folder-dialog .grid-search-result:selected:hover, .app-folder-dialog .overview-tile:checked:hover, .app-folder-dialog .grid-search-result:checked:hover {
-         background-color: #686868; }
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 7%); }
 +      .app-folder-dialog .overview-tile:highlighted:active, .app-folder-dialog .grid-search-result:highlighted:active, .app-folder-dialog .overview-tile:selected:active, .app-folder-dialog .grid-search-result:selected:active, .app-folder-dialog .overview-tile:checked:active, .app-folder-dialog .grid-search-result:checked:active {
-       color: rgba(245, 245, 245, 0.4);
++        background-color: st-lighten(st-lighten(#3d3d3d, 8%), 9%); }
 +    .app-folder-dialog .overview-tile:insensitive, .app-folder-dialog .grid-search-result:insensitive {
-       background-color: rgba(28, 113, 216, 0.2);
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.8); }
++      color: st-transparentize(whitesmoke, 0.6);
 +      background-color: #3d3d3d; }
 +    .app-folder-dialog .overview-tile:drop, .app-folder-dialog .grid-search-result:drop {
-     background-color: #3a3a3a; }
++      background-color: st-transparentize(-st-accent-color, 0.8);
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.2); }
 +
 +.rename-folder-popup .rename-folder-popup-item {
 +  spacing: 6px; }
 +  .rename-folder-popup .rename-folder-popup-item:ltr, .rename-folder-popup .rename-folder-popup-item:rtl {
 +    padding: 0 12px; }
 +
 +.page-indicator {
 +  padding: 6px 12px 0;
 +  transition-duration: 400ms; }
 +  .page-indicator .page-indicator-icon {
 +    width: 10px;
 +    height: 10px;
 +    border-radius: 999px;
 +    background-color: whitesmoke;
 +    transition-duration: 400ms; }
 +
 +.apps-scroll-view {
 +  padding: 0; }
 +
 +.system-action-icon {
 +  background-color: rgba(245, 245, 245, 0.1);
 +  color: whitesmoke;
 +  border-radius: 999px;
 +  icon-size: 48px; }
 +
 +.page-navigation-hint.dnd {
 +  background: rgba(255, 255, 255, 0.1); }
 +
 +.page-navigation-hint.next:ltr, .page-navigation-hint.previous:rtl {
 +  background-gradient-start: rgba(255, 255, 255, 0.05);
 +  background-gradient-end: transparent;
 +  background-gradient-direction: horizontal;
 +  border-radius: 24px 0px 0px 24px; }
 +
 +.page-navigation-hint.previous:ltr, .page-navigation-hint.next:rtl {
 +  background-gradient-start: transparent;
 +  background-gradient-end: rgba(255, 255, 255, 0.05);
 +  background-gradient-direction: horizontal;
 +  border-radius: 0px 24px 24px 0px; }
 +
 +.page-navigation-arrow {
 +  margin: 6px;
 +  padding: 18px;
 +  width: 24px;
 +  height: 24px;
 +  border-radius: 999px;
 +  transition-duration: 100ms;
 +  color: whitesmoke;
 +  background-color: #282828; }
 +  .page-navigation-arrow > StIcon {
 +    color: whitesmoke; }
 +  .page-navigation-arrow:hover {
 +    color: whitesmoke;
-     background-color: #3f3f3f; }
++    background-color: st-lighten(#282828, 7%); }
 +  .page-navigation-arrow:active {
 +    color: whitesmoke;
-       background-color: #515151; }
++    background-color: st-lighten(#282828, 9%); }
 +    .page-navigation-arrow:active:hover {
-       background-color: #3d4147; }
++      background-color: st-lighten(st-lighten(#282828, 9%), 7%); }
 +    .page-navigation-arrow:active:focus {
-   border: 3px solid #1c71d8;
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 9%), 5%); }
 +
 +/* Workspace pager */
 +.workspace-thumbnails {
 +  visible-width: 32px;
 +  spacing: 6px;
 +  padding: 6px; }
 +  .workspace-thumbnails .workspace-thumbnail {
 +    color: whitesmoke;
 +    background-color: #4e4e4e;
 +    border-radius: 4px;
 +    border: 1px solid transparent; }
 +  .workspace-thumbnails .placeholder {
 +    background-image: url("resource:///org/gnome/shell/theme/workspace-placeholder.svg");
 +    background-size: contain;
 +    width: 18px; }
 +
 +.workspace-thumbnail-indicator {
-   background-color: rgba(155, 194, 242, 0.3);
-   box-shadow: 0 0 2px 2px #6ea7ec; }
++  border: 3px solid -st-accent-color;
 +  border-radius: 8px; }
 +
 +.ripple-pointer-location {
 +  width: 50px;
 +  height: 50px;
 +  border-radius: 25px;
-   -pie-border-color: #1c71d8;
-   -pie-background-color: rgba(200, 222, 248, 0.3); }
++  background-color: st-lighten(st-transparentize(-st-accent-color, 0.7), 30%);
++  box-shadow: 0 0 2px 2px st-lighten(-st-accent-color, 20%); }
 +
 +.pie-timer {
 +  width: 60px;
 +  height: 60px;
 +  -pie-border-width: 3px;
-   border: 2px solid #1c71d8; }
++  -pie-border-color: -st-accent-color;
++  -pie-background-color: st-lighten(st-transparentize(-st-accent-color, 0.7), 40%); }
 +
 +.magnifier-zoom-region {
-   background-color: rgba(28, 113, 216, 0.3);
-   border: 1px solid #1c71d8; }
++  border: 2px solid -st-accent-color; }
 +  .magnifier-zoom-region.full-screen {
 +    border-width: 0; }
 +
 +.select-area-rubberband {
-   background-color: rgba(28, 113, 216, 0.5);
-   border: 1px solid #1c71d8; }
++  background-color: st-transparentize(-st-accent-color, 0.7);
++  border: 1px solid -st-accent-color; }
 +
 +.user-icon {
 +  background-size: contain;
 +  border-radius: 999px;
 +  icon-size: 64px;
 +  background-color: rgba(255, 255, 255, 0.05);
 +  color: #ffffff; }
 +  .user-icon StIcon {
 +    padding: 12px; }
 +  .user-icon.user-avatar {
 +    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1); }
 +
 +.lightbox {
 +  background-color: black; }
 +
 +.flashspot {
 +  background-color: white; }
 +
 +.hidden {
 +  color: transparent; }
 +
 +.caps-lock-warning-label {
 +  text-align: center;
 +  padding-bottom: 8px;
 +  color: #f5c211; }
 +
 +/* Workspace animation */
 +.workspace-animation {
 +  background-color: #353535; }
 +
 +/* Tiled window previews */
 +.tile-preview {
-   background-color: #626262; }
++  background-color: st-transparentize(-st-accent-color, 0.5);
++  border: 1px solid -st-accent-color; }
 +
 +/* On-screen Keyboard */
 +#keyboard {
 +  background-color: #353535;
 +  box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.02); }
 +  #keyboard .page-indicator {
 +    padding: 6px; }
 +    #keyboard .page-indicator .page-indicator-icon {
 +      width: 8px;
 +      height: 8px; }
 +
 +.key-container {
 +  padding: 4px;
 +  spacing: 4px; }
 +
 +.keyboard-key {
 +  font-size: 1.455em;
 +  font-weight: bold;
 +  min-height: 1.2em;
 +  min-width: 1.2em;
 +  border-width: 1px;
 +  border-style: solid;
 +  border-radius: 10px;
 +  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.05);
 +  color: #ffffff;
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: #d2d7dc; }
++  background-color: st-mix(#ffffff, #4d4d4d, 12%); }
 +  .keyboard-key:focus {
 +    color: #282828;
-       background-color: #c9cdd2; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, st-mix(#282828, whitesmoke, 12%), 5%); }
 +    .keyboard-key:focus:hover {
-     background-color: #585858; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, whitesmoke, 12%), 4%), 5%); }
 +  .keyboard-key:hover {
 +    color: #ffffff;
-     background-color: #4b4b4b; }
++    background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 4%); }
 +  .keyboard-key:active {
 +    color: #ffffff;
-       background-color: #414141; }
++    background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%); }
 +    .keyboard-key:active:hover {
-       background-color: #494d52; }
++      background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%), 4%); }
 +    .keyboard-key:active:focus {
-     background-color: #4e4e4e; }
++      background-color: st-mix(-st-accent-color, st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%), 5%); }
 +  .keyboard-key:checked {
 +    color: #ffffff;
-       background-color: #434343; }
++    background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%); }
 +    .keyboard-key:checked:hover {
-       background-color: #373737; }
++      background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%), 4%); }
 +    .keyboard-key:checked:active {
-     background-color: #494949;
++      background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%), 9%); }
 +  .keyboard-key:grayed {
 +    background-color: #ededed;
 +    color: #ffffff;
 +    border-color: rgba(255, 255, 255, 0.1); }
 +  .keyboard-key.default-key {
 +    color: #ffffff;
-       background-color: #3f3f3f; }
++    background-color: st-mix(#ffffff, #303030, 12%);
 +    border-radius: 10px; }
 +    .keyboard-key.default-key:hover {
 +      color: #ffffff;
-       background-color: #323232; }
++      background-color: st-darken(st-mix(#ffffff, #303030, 12%), 4%); }
 +    .keyboard-key.default-key:active {
 +      color: #ffffff;
-         background-color: #282828; }
++      background-color: st-darken(st-mix(#ffffff, #303030, 12%), 9%); }
 +      .keyboard-key.default-key:active:hover {
-         background-color: #31353a; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #303030, 12%), 9%), 4%); }
 +      .keyboard-key.default-key:active:focus {
-       background-color: #353535; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(#ffffff, #303030, 12%), 9%), 5%); }
 +    .keyboard-key.default-key:checked {
 +      color: #ffffff;
-         background-color: #2a2a2a; }
++      background-color: st-darken(st-mix(#ffffff, #303030, 12%), 8%); }
 +      .keyboard-key.default-key:checked:hover {
-         background-color: #1e1e1e; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #303030, 12%), 8%), 4%); }
 +      .keyboard-key.default-key:checked:active {
-       border-color: #2a7ee3;
-       background-color: #1c71d8; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #303030, 12%), 8%), 9%); }
 +    .keyboard-key.default-key:latched {
-     color: #ffffff;
-     background-color: #3782dd;
++      border-color: st-lighten(-st-accent-color, 5%);
++      background-color: -st-accent-color; }
 +  .keyboard-key.enter-key {
-       color: #ffffff;
-       background-color: #2677da; }
++    color: -st-accent-fg-color;
++    background-color: st-mix(-st-accent-fg-color, -st-accent-color, 12%);
 +    border-radius: 10px;
 +    color: #ffffff; }
 +    .keyboard-key.enter-key:hover {
-       color: #ffffff;
-       background-color: #216bc5; }
++      color: -st-accent-fg-color;
++      background-color: st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 4%); }
 +    .keyboard-key.enter-key:active {
-         background-color: #1e62b3; }
++      color: -st-accent-fg-color;
++      background-color: st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 9%); }
 +      .keyboard-key.enter-key:active:hover {
-         background-color: #216bc6; }
++        background-color: st-darken(st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 9%), 4%); }
 +      .keyboard-key.enter-key:active:focus {
-       color: #ffffff;
-       background-color: #226ec9; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 9%), 5%); }
 +    .keyboard-key.enter-key:checked {
-         background-color: #1f64b8; }
++      color: -st-accent-fg-color;
++      background-color: st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 8%); }
 +      .keyboard-key.enter-key:checked:hover {
-         background-color: #1c58a2; }
++        background-color: st-darken(st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 8%), 4%); }
 +      .keyboard-key.enter-key:checked:active {
-     background-color: #626262;
++        background-color: st-darken(st-darken(st-mix(-st-accent-fg-color, -st-accent-color, 12%), 8%), 9%); }
 +  .keyboard-key.shift-key-uppercase {
 +    background-color: gray;
 +    color: #353535; }
 +    .keyboard-key.shift-key-uppercase:hover {
 +      background-color: #8c8c8c;
 +      color: #424242; }
 +  .keyboard-key StIcon {
 +    icon-size: 24px; }
 +
 +.keyboard-subkeys {
 +  -arrow-border-radius: 16px;
 +  -arrow-background-color: #353535;
 +  -arrow-border-width: 1px;
 +  -arrow-border-color: #4c4c4c;
 +  -arrow-base: 20px;
 +  -arrow-rise: 10px;
 +  -boxpointer-gap: 6px;
 +  padding: 6px; }
 +  .keyboard-subkeys .keyboard-key {
 +    color: #ffffff;
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-       background-color: #d2d7dc; }
++    background-color: st-mix(#ffffff, #4d4d4d, 12%);
 +    border-radius: 10px; }
 +    .keyboard-subkeys .keyboard-key:focus {
 +      color: #282828;
-         background-color: #c9cdd2; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, st-mix(#282828, whitesmoke, 12%), 5%); }
 +      .keyboard-subkeys .keyboard-key:focus:hover {
-       background-color: #585858; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, whitesmoke, 12%), 4%), 5%); }
 +    .keyboard-subkeys .keyboard-key:hover {
 +      color: #ffffff;
-       background-color: #4b4b4b; }
++      background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 4%); }
 +    .keyboard-subkeys .keyboard-key:active {
 +      color: #ffffff;
-         background-color: #414141; }
++      background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%); }
 +      .keyboard-subkeys .keyboard-key:active:hover {
-         background-color: #494d52; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%), 4%); }
 +      .keyboard-subkeys .keyboard-key:active:focus {
-       background-color: #4e4e4e; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%), 5%); }
 +    .keyboard-subkeys .keyboard-key:checked {
 +      color: #ffffff;
-         background-color: #434343; }
++      background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%); }
 +      .keyboard-subkeys .keyboard-key:checked:hover {
-         background-color: #373737; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%), 4%); }
 +      .keyboard-subkeys .keyboard-key:checked:active {
-   border-color: #2a7ee3;
-   background-color: #1c71d8; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%), 9%); }
 +
 +.emoji-page .keyboard-key {
 +  background-color: transparent;
 +  border: none;
 +  color: initial; }
 +
 +.emoji-panel .keyboard-key:latched {
-       box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-       background-color: #d2d7dc; }
++  border-color: st-lighten(-st-accent-color, 5%);
++  background-color: -st-accent-color; }
 +
 +.word-suggestions {
 +  spacing: 12px;
 +  min-height: 17pt;
 +  padding: 12px;
 +  color: #ffffff; }
 +  .word-suggestions StButton {
 +    margin: 0 3px;
 +    min-width: 32px;
 +    border-radius: 4px;
 +    padding: 0px 18px;
 +    background-color: transparent;
 +    border-color: transparent;
 +    box-shadow: none; }
 +    .word-suggestions StButton:insensitive {
 +      background-color: transparent !important; }
 +    .word-suggestions StButton:focus {
 +      color: #282828;
-         background-color: #c9cdd2; }
++      box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++      background-color: st-mix(-st-accent-color, st-mix(#282828, whitesmoke, 12%), 5%); }
 +      .word-suggestions StButton:focus:hover {
-       background-color: #585858; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(#282828, whitesmoke, 12%), 4%), 5%); }
 +    .word-suggestions StButton:hover {
 +      color: #ffffff;
-       background-color: #4b4b4b; }
++      background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 4%); }
 +    .word-suggestions StButton:active {
 +      color: #ffffff;
-         background-color: #414141; }
++      background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%); }
 +      .word-suggestions StButton:active:hover {
-         background-color: #494d52; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%), 4%); }
 +      .word-suggestions StButton:active:focus {
-       background-color: #4e4e4e; }
++        background-color: st-mix(-st-accent-color, st-darken(st-mix(#ffffff, #4d4d4d, 12%), 9%), 5%); }
 +    .word-suggestions StButton:checked {
 +      color: #ffffff;
-         background-color: #434343; }
++      background-color: st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%); }
 +      .word-suggestions StButton:checked:hover {
-         background-color: #373737; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%), 4%); }
 +      .word-suggestions StButton:checked:active {
-   #LookingGlassDialog StBoxLayout#EvalBox {
-     padding: 4px;
-     spacing: 6px;
-     padding: 6px; }
-   #LookingGlassDialog StBoxLayout#ResultsArea {
-     spacing: 6px;
-     padding: 6px; }
- 
- .lg-dialog StEntry {
-   min-height: 1.5em; }
++        background-color: st-darken(st-darken(st-mix(#ffffff, #4d4d4d, 12%), 8%), 9%); }
 +
 +/* Looking Glass */
++.lg-dialog StEntry {
++  min-height: 1.5em; }
++
++.lg-dialog .shell-link {
++  color: st-lighten(-st-accent-color, 20%); }
++  .lg-dialog .shell-link:hover {
++    color: st-lighten(st-lighten(-st-accent-color, 20%), 10%); }
++  .lg-dialog .shell-link:active {
++    color: st-darken(st-lighten(-st-accent-color, 20%), 10%); }
++
++.lg-dialog .actor-link {
++  color: st-darken(#ffffff, 20%); }
++  .lg-dialog .actor-link:hover {
++    color: #ffffff; }
++  .lg-dialog .actor-link:active {
++    color: st-lighten(#ffffff, 20%); }
++  .lg-dialog .actor-link StIcon {
++    icon-size: 12px; }
++
++.lg-completions-text {
++  font-style: italic; }
++
 +#LookingGlassDialog {
 +  background-color: rgba(53, 53, 53, 0.98);
 +  color: #ffffff;
 +  border-radius: 16px;
 +  margin-top: 4px;
 +  border: 2px solid transparent;
 +  padding: 6px;
 +  spacing: 6px;
 +  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.05); }
 +  #LookingGlassDialog > #Toolbar {
 +    border: none;
 +    padding: 6px;
 +    border-radius: 0;
 +    background-color: transparent;
 +    spacing: 6px; }
 +    #LookingGlassDialog > #Toolbar .lg-toolbar-button {
 +      padding: 6px 12px; }
 +      #LookingGlassDialog > #Toolbar .lg-toolbar-button > StIcon {
 +        icon-size: 16px; }
 +  #LookingGlassDialog .labels {
 +    spacing: 6px; }
 +  #LookingGlassDialog .notebook-tab {
++    background-color: transparent;
 +    -natural-hpadding: 12px;
 +    -minimum-hpadding: 12px;
 +    padding: 6px 12px; }
- .lg-dialog .shell-link {
-   color: #1c71d8; }
-   .lg-dialog .shell-link:hover {
-     color: #418ce6; }
-   .lg-dialog .shell-link:active {
-     color: #1659ab; }
++    #LookingGlassDialog .notebook-tab:selected {
++      color: #ffffff;
++      background-color: st-lighten(st-mix(#ffffff, #353535, 12%), 9%); }
++      #LookingGlassDialog .notebook-tab:selected:hover {
++        background-color: st-lighten(st-lighten(st-mix(#ffffff, #353535, 12%), 9%), 4%); }
++      #LookingGlassDialog .notebook-tab:selected:focus {
++        background-color: st-mix(-st-accent-color, st-lighten(st-mix(#ffffff, #353535, 12%), 9%), 5%); }
 +
- .lg-dialog .actor-link {
-   color: #7a7a7a; }
-   .lg-dialog .actor-link:hover {
-     color: #adadad; }
-   .lg-dialog .actor-link:active {
-     color: #474747; }
-   .lg-dialog .actor-link StIcon {
-     icon-size: 12px; }
++#LookingGlassPropertyInspector {
++  background-color: #353535;
++  color: #ffffff;
++  border-radius: 16px;
++  border: 1px solid rgba(255, 255, 255, 0.1);
++  padding: 12px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-title {
++    spacing: 4px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-close-button,
++  #LookingGlassPropertyInspector .lg-obj-inspector-button {
++    padding: 6px 12px; }
++  #LookingGlassPropertyInspector .lg-obj-inspector-close-button {
++    margin: 4px;
++    padding: 6px;
++    border-radius: 999px; }
++    #LookingGlassPropertyInspector .lg-obj-inspector-close-button > StIcon {
++      icon-size: 16px; }
 +
- .lg-completions-text {
-   font-style: italic; }
++#LookingGlassEvaluator {
++  padding: 6px; }
++  #LookingGlassEvaluator .evaluator-results {
++    spacing: 6px; }
 +
- .lg-obj-inspector-title {
++#LookingGlassWindows {
++  padding: 6px;
++  spacing: 6px; }
++  #LookingGlassWindows .lg-window {
++    color: #ffffff;
++    background-color: st-mix(#ffffff, #353535, 12%);
++    margin: 0;
++    padding: 12px; }
 +
- .lg-obj-inspector-button {
-   border: 1px solid rgba(40, 40, 40, 0.15);
-   padding: 4px;
-   border-radius: 8px; }
-   .lg-obj-inspector-button:hover {
-     border: 1px solid #282828; }
++#LookingGlassExtensions .lg-extensions-list {
++  padding: 6px;
 +  spacing: 6px; }
 +
- #lookingGlassExtensions {
-   padding: 6px; }
++#LookingGlassExtensions .lg-extension {
++  color: #ffffff;
++  background-color: st-mix(#ffffff, #353535, 12%);
++  margin: 0;
++  spacing: 4px;
++  padding: 12px; }
++  #LookingGlassExtensions .lg-extension .lg-extension-name {
++    color: #ffffff !important; }
++  #LookingGlassExtensions .lg-extension .lg-extension-meta {
++    spacing: 12px; }
 +
- .lg-extensions-list {
++#LookingGlassExtensions .lg-extensions-none {
++  color: rgba(255, 255, 255, 0.5); }
 +
-   spacing: 6px; }
- 
- .lg-extension-meta {
-   spacing: 6px; }
++#LookingGlassActors {
 +  padding: 6px;
- #LookingGlassPropertyInspector {
-   background: whitesmoke;
-   border: 1px solid rgba(40, 40, 40, 0.15);
-   border-radius: 8px;
-   padding: 6px; }
++  spacing: 4px; }
 +
- .lg-debug-flag-button {
-   color: #ffffff; }
-   .lg-debug-flag-button StLabel {
-     padding: 6px, 12px; }
-   .lg-debug-flag-button:hover {
-     color: white; }
-   .lg-debug-flag-button:active {
-     color: #cccccc; }
- 
- .lg-debug-flags-header {
-   padding-top: 12px;
-   padding: 6px; }
++#LookingGlassDebugFlags .lg-debug-flags-header {
++  padding: 6px;
++  padding-top: 12px; }
 +
-     box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-     background-color: rgba(37, 60, 87, 0.2875); }
++#LookingGlassDebugFlags .lg-debug-flag-button {
++  padding: 9px 12px;
++  margin-bottom: 6px; }
++  #LookingGlassDebugFlags .lg-debug-flag-button StLabel {
++    font-weight: normal !important; }
++  #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch {
++    background: rgba(255, 255, 255, 0.15); }
++    #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:hover {
++      background: rgba(255, 255, 255, 0.2); }
++    #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:checked {
++      background: -st-accent-color;
++      color: -st-accent-fg-color; }
++      #LookingGlassDebugFlags .lg-debug-flag-button .toggle-switch:checked:hover {
++        background-color: st-lighten(-st-accent-color, 5%);
++        color: st-lighten(-st-accent-fg-color, 5%); }
 +
 +.login-dialog,
 +.unlock-dialog {
 +  color: whitesmoke; }
 +  .login-dialog .caps-lock-warning-label,
 +  .login-dialog .login-dialog-message-warning,
 +  .unlock-dialog .caps-lock-warning-label,
 +  .unlock-dialog .login-dialog-message-warning {
 +    color: whitesmoke; }
 +  .login-dialog .login-dialog-prompt-layout,
 +  .unlock-dialog .login-dialog-prompt-layout {
 +    width: 25em;
 +    spacing: 9px; }
 +
 +.login-dialog-button.cancel-button {
 +  padding: 9px; }
 +
 +.login-dialog-button-box {
 +  spacing: 12px; }
 +
 +.conflicting-session-dialog-content {
 +  spacing: 20px; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-title {
 +    text-align: center;
 +    margin-bottom: 5px; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-desc {
 +    text-align: center; }
 +  .conflicting-session-dialog-content .conflicting-session-dialog-desc-warning {
 +    text-align: center;
 +    color: #f5c211; }
 +
 +.login-dialog-logo-bin {
 +  margin: 3em 0; }
 +
 +.login-dialog-banner-view {
 +  max-width: 25em; }
 +  .login-dialog-banner-view .login-dialog-banner {
 +    color: gainsboro; }
 +
 +.login-dialog-message {
 +  text-align: center; }
 +
 +.login-dialog-message-hint, .login-dialog-message {
 +  color: gainsboro;
 +  min-height: 2.75em; }
 +
 +.login-dialog-user-selection-box {
 +  padding-top: 4em;
 +  padding-bottom: 8em; }
 +
 +.login-dialog-not-listed-label {
 +  padding: 6px; }
 +
 +.login-dialog-not-listed-button {
 +  color: whitesmoke;
 +  background-color: #282828;
 +  padding: 0 6px;
 +  margin: 6px; }
 +  .login-dialog-not-listed-button:focus {
 +    color: whitesmoke;
-       background-color: #383d42; }
++    box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++    background-color: st-mix(-st-accent-color, rgba(40, 40, 40, 0.25), 5%); }
 +    .login-dialog-not-listed-button:focus:hover {
-     background-color: #3a3a3a; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 7%), 5%); }
 +  .login-dialog-not-listed-button:hover {
 +    color: whitesmoke;
-     background-color: #3f3f3f; }
++    background-color: st-lighten(#282828, 7%); }
 +  .login-dialog-not-listed-button:active {
 +    color: whitesmoke;
-       background-color: #515151; }
++    background-color: st-lighten(#282828, 9%); }
 +    .login-dialog-not-listed-button:active:hover {
-       background-color: #3d4147; }
++      background-color: st-lighten(st-lighten(#282828, 9%), 7%); }
 +    .login-dialog-not-listed-button:active:focus {
-     background-color: #1c71d8;
-     color: #ffffff; }
++      background-color: st-mix(-st-accent-color, st-lighten(#282828, 9%), 5%); }
 +
 +.login-dialog-auth-list-view {
 +  -st-vfade-offset: 3em; }
 +
 +.login-dialog-auth-list {
 +  spacing: 6px;
 +  margin-left: 2em; }
 +
 +.login-dialog-auth-list-title {
 +  margin-left: 2em; }
 +
 +.login-dialog-auth-list-item {
 +  border-radius: 16px;
 +  padding: 4px;
 +  color: darkgray; }
 +  .login-dialog-auth-list-item:focus, .login-dialog-auth-list-item:selected {
-       background-color: #414141;
++    background-color: -st-accent-color;
++    color: -st-accent-fg-color; }
 +
 +.login-dialog-auth-list-label:ltr {
 +  padding-left: 15px;
 +  text-align: left; }
 +
 +.login-dialog-auth-list-label:rtl {
 +  padding-right: 15px;
 +  text-align: right; }
 +
 +.login-dialog-user-list-view {
 +  width: 25em;
 +  -st-vfade-offset: 3em; }
 +  .login-dialog-user-list-view .login-dialog-user-list {
 +    margin: 0 8px;
 +    spacing: 12px; }
 +    .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item {
 +      color: whitesmoke;
-         box-shadow: inset 0 0 0 2px rgba(28, 113, 216, 0.5) !important;
-         background-color: #3f4349; }
++      background-color: st-mix(whitesmoke, #282828, 12%);
 +      border-radius: 16px;
 +      padding: 9px; }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:selected, .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:focus {
 +        color: whitesmoke;
-           background-color: #494d52; }
++        box-shadow: inset 0 0 0 2px st-transparentize(-st-accent-color, 0.5) !important;
++        background-color: st-mix(-st-accent-color, st-mix(whitesmoke, #282828, 12%), 5%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:selected:hover, .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:focus:hover {
-         background-color: #4b4b4b; }
++          background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 12%), 4%), 5%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:hover {
 +        color: whitesmoke;
-         background-color: #585858; }
++        background-color: st-lighten(st-mix(whitesmoke, #282828, 12%), 4%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active {
 +        color: whitesmoke;
-           background-color: #626262; }
++        background-color: st-lighten(st-mix(whitesmoke, #282828, 12%), 9%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active:hover {
-           background-color: #55595e; }
++          background-color: st-lighten(st-lighten(st-mix(whitesmoke, #282828, 12%), 9%), 4%); }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:active:focus {
-         border-color: #1c71d8; }
++          background-color: st-mix(-st-accent-color, st-lighten(st-mix(whitesmoke, #282828, 12%), 9%), 5%); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item .user-icon {
 +        border: 2px solid transparent; }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item .login-dialog-timed-login-indicator {
 +        height: 2px;
 +        margin-top: 6px;
 +        background-color: rgba(245, 245, 245, 0.7); }
 +      .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:logged-in .user-icon {
-           background-color: rgba(28, 113, 216, 0.3); }
++        border-color: -st-accent-color; }
 +        .login-dialog-user-list-view .login-dialog-user-list .login-dialog-user-list-item:logged-in .user-icon StIcon {
-     font-weight: 200; }
++          background-color: st-transparentize(-st-accent-color, 0.7); }
 +
 +.unlock-dialog {
 +  background-color: transparent; }
 +
 +.screen-shield-background {
 +  background: black;
 +  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6); }
 +
 +#lockDialogGroup {
 +  background-color: #282828; }
 +
 +.unlock-dialog-clock {
 +  color: whitesmoke;
 +  spacing: 2em; }
 +  .unlock-dialog-clock .unlock-dialog-clock-time {
 +    font-size: 6.546em;
-     background-color: rgba(28, 113, 216, 0.5); }
++    font-weight: 800; }
 +  .unlock-dialog-clock .unlock-dialog-clock-date {
 +    font-weight: 400; }
 +  .unlock-dialog-clock .unlock-dialog-clock-hint {
 +    margin-top: 2em;
 +    padding: 6px 18px;
 +    border-radius: 16px;
 +    font-weight: bold; }
 +
 +#unlockDialogNotifications StButton#vhandle, #unlockDialogNotifications StButton#hhandle {
 +  background-color: rgba(245, 245, 245, 0.3); }
 +  #unlockDialogNotifications StButton#vhandle:hover, #unlockDialogNotifications StButton#vhandle:focus, #unlockDialogNotifications StButton#hhandle:hover, #unlockDialogNotifications StButton#hhandle:focus {
 +    background-color: rgba(245, 245, 245, 0.5); }
 +  #unlockDialogNotifications StButton#vhandle:active, #unlockDialogNotifications StButton#hhandle:active {
-       padding: 24px; }
++    background-color: st-transparentize(-st-accent-color, 0.5); }
 +
 +.unlock-dialog-notifications-container {
 +  margin: 12px;
 +  spacing: 6px;
 +  width: 25em;
 +  background-color: transparent; }
 +  .unlock-dialog-notifications-container .summary-notification-stack-scrollview {
 +    padding-top: 0;
 +    padding-bottom: 0; }
 +  .unlock-dialog-notifications-container .notification,
 +  .unlock-dialog-notifications-container .unlock-dialog-notification-source {
 +    padding: 12px 16px;
 +    border: none;
 +    background-color: rgba(245, 245, 245, 0.1);
 +    color: whitesmoke;
 +    border-radius: 16px; }
 +    .unlock-dialog-notifications-container .notification.critical,
 +    .unlock-dialog-notifications-container .unlock-dialog-notification-source.critical {
 +      background-color: rgba(245, 245, 245, 0.2); }
 +
 +.unlock-dialog-notification-icon {
 +  icon-size: 32px; }
 +
 +.unlock-dialog-notification-label {
 +  padding-left: 12px;
 +  padding-right: 0; }
 +  .unlock-dialog-notification-label:rtl {
 +    padding-right: 12px;
 +    padding-left: 0; }
 +
 +.unlock-dialog-notification-count-text {
 +  font-weight: bold;
 +  padding: 0 12px;
 +  color: whitesmoke;
 +  background-color: rgba(245, 245, 245, 0.1);
 +  border-radius: 999px; }
 +
 +.login-dialog .user-widget .user-widget-label,
 +.unlock-dialog .user-widget .user-widget-label {
 +  color: whitesmoke; }
 +
 +.login-dialog .user-widget .user-icon,
 +.unlock-dialog .user-widget .user-icon {
 +  background-color: rgba(245, 245, 245, 0.13);
 +  color: whitesmoke; }
 +
 +.login-dialog .user-widget.horizontal,
 +.unlock-dialog .user-widget.horizontal {
 +  spacing: 18px; }
 +
 +.login-dialog .user-widget.vertical,
 +.unlock-dialog .user-widget.vertical {
 +  spacing: 24px; }
 +  .login-dialog .user-widget.vertical .user-widget-label,
 +  .unlock-dialog .user-widget.vertical .user-widget-label {
++    font-weight: 400;
++    font-size: 1.818em;
 +    text-align: center;
 +    margin-bottom: .75em; }
 +  .login-dialog .user-widget.vertical .user-icon,
 +  .unlock-dialog .user-widget.vertical .user-icon {
 +    icon-size: 160px; }
 +    .login-dialog .user-widget.vertical .user-icon StIcon,
 +    .unlock-dialog .user-widget.vertical .user-icon StIcon {
++      padding: 30px; }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ccab0ca5a2966709000ab478ad0176b451c752ce
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++# Copied from Jasmine, use the original project's coding style
++lib/jasmine.js
++test/jasmineIntegrationTest.js
++
++# Deliberate syntax error
++test/fixtures/syntaxErrorSpec.js
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6ef6abc3663fc4cb43370f3282ca7174c778f0b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,235 @@@
++---
++env:
++  es6: true
++extends: 'eslint:recommended'
++rules:
++  array-bracket-newline:
++    - error
++    - consistent
++  array-bracket-spacing:
++    - error
++    - never
++  array-callback-return: error
++  arrow-parens:
++    - error
++    - as-needed
++  arrow-spacing: error
++  block-scoped-var: error
++  block-spacing: error
++  brace-style: error
++  camelcase:
++    - error
++    - properties: never
++      allow: [^vfunc_, ^on_, _instance_init]
++  comma-dangle:
++    - error
++    - arrays: always-multiline
++      objects: always-multiline
++      functions: never
++  comma-spacing:
++    - error
++    - before: false
++      after: true
++  comma-style:
++    - error
++    - last
++  computed-property-spacing: error
++  curly:
++    - error
++    - multi-or-nest
++    - consistent
++  dot-location:
++    - error
++    - property
++  eol-last: error
++  eqeqeq: error
++  func-call-spacing: error
++  func-name-matching: error
++  func-style:
++    - error
++    - declaration
++    - allowArrowFunctions: true
++  indent:
++    - error
++    - 4
++    - ignoredNodes:
++      # Allow not indenting the body of GObject.registerClass, since in the
++      # future it's intended to be a decorator
++      - 'CallExpression[callee.object.name=GObject][callee.property.name=registerClass] > ClassExpression:first-child'
++      # Allow dedenting chained member expressions
++      MemberExpression: 'off'
++  key-spacing:
++    - error
++    - beforeColon: false
++      afterColon: true
++  keyword-spacing:
++    - error
++    - before: true
++      after: true
++  linebreak-style:
++    - error
++    - unix
++  lines-between-class-members: error
++  max-nested-callbacks: error
++  max-statements-per-line: error
++  new-parens: error
++  no-array-constructor: error
++  no-await-in-loop: error
++  no-caller: error
++  no-constant-condition:
++    - error
++    - checkLoops: false
++  no-div-regex: error
++  no-empty:
++    - error
++    - allowEmptyCatch: true
++  no-extra-bind: error
++  no-extra-parens:
++    - error
++    - all
++    - conditionalAssign: false
++      nestedBinaryExpressions: false
++      returnAssign: false
++  no-implicit-coercion:
++    - error
++    - allow:
++      - '!!'
++  no-invalid-this: error
++  no-iterator: error
++  no-label-var: error
++  no-lonely-if: error
++  no-loop-func: error
++  no-nested-ternary: error
++  no-new-object: error
++  no-new-wrappers: error
++  no-octal-escape: error
++  no-proto: error
++  no-prototype-builtins: 'off'
++  no-restricted-properties:
++    - error
++    - object: imports
++      property: format
++      message: Use template strings
++    - object: Lang
++      property: copyProperties
++      message: Use Object.assign()
++    - object: Lang
++      property: bind
++      message: Use arrow notation or Function.prototype.bind()
++    - object: Lang
++      property: Class
++      message: Use ES6 classes
++  no-restricted-syntax:
++    - error
++    - selector: >-
++        MethodDefinition[key.name="_init"] >
++        FunctionExpression[params.length=1] >
++        BlockStatement[body.length=1]
++        CallExpression[arguments.length=1][callee.object.type="Super"][callee.property.name="_init"] >
++        Identifier:first-child
++      message: _init() that only calls super._init() is unnecessary
++    - selector: >-
++        MethodDefinition[key.name="_init"] >
++        FunctionExpression[params.length=0] >
++        BlockStatement[body.length=1]
++        CallExpression[arguments.length=0][callee.object.type="Super"][callee.property.name="_init"]
++      message: _init() that only calls super._init() is unnecessary
++    - selector: BinaryExpression[operator="instanceof"][right.name="Array"]
++      message: Use Array.isArray()
++  no-return-assign: error
++  no-return-await: error
++  no-self-compare: error
++  no-shadow: error
++  no-shadow-restricted-names: error
++  no-spaced-func: error
++  no-tabs: error
++  no-template-curly-in-string: error
++  no-throw-literal: error
++  no-trailing-spaces: error
++  no-undef-init: error
++  no-unneeded-ternary: error
++  no-unused-expressions: error
++  no-unused-vars:
++    - error
++    # Vars use a suffix _ instead of a prefix because of file-scope private vars
++    - varsIgnorePattern: (^unused|_$)
++      argsIgnorePattern: ^(unused|_)
++  no-useless-call: error
++  no-useless-computed-key: error
++  no-useless-concat: error
++  no-useless-constructor: error
++  no-useless-rename: error
++  no-useless-return: error
++  no-whitespace-before-property: error
++  no-with: error
++  nonblock-statement-body-position:
++    - error
++    - below
++  object-curly-newline:
++    - error
++    - consistent: true
++  object-curly-spacing: error
++  object-shorthand: error
++  operator-assignment: error
++  operator-linebreak: error
++  prefer-const: error
++  prefer-destructuring: error
++  prefer-numeric-literals: error
++  prefer-promise-reject-errors: error
++  prefer-rest-params: error
++  prefer-spread: error
++  prefer-template: error
++  quotes:
++    - error
++    - single
++    - avoidEscape: true
++  require-await: error
++  rest-spread-spacing: error
++  semi:
++    - error
++    - always
++  semi-spacing:
++    - error
++    - before: false
++      after: true
++  semi-style: error
++  space-before-blocks: error
++  space-before-function-paren:
++    - error
++    - named: never
++      # for `function ()` and `async () =>`, preserve space around keywords
++      anonymous: always
++      asyncArrow: always
++  space-in-parens: error
++  space-infix-ops:
++    - error
++    - int32Hint: false
++  space-unary-ops: error
++  spaced-comment: error
++  switch-colon-spacing: error
++  symbol-description: error
++  template-curly-spacing: error
++  template-tag-spacing: error
++  unicode-bom: error
++  valid-jsdoc:
++    - error
++    - requireReturn: false
++  wrap-iife:
++    - error
++    - inside
++  yield-star-spacing: error
++  yoda: error
++globals:
++  ARGV: readonly
++  Debugger: readonly
++  GIRepositoryGType: readonly
++  globalThis: readonly
++  imports: readonly
++  Intl: readonly
++  log: readonly
++  logError: readonly
++  print: readonly
++  printerr: readonly
++parserOptions:
++  ecmaVersion: 2020
++  sourceType: module
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b796a0adb441758bdc246583168305ef1aa71818
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++{
++    "disallowEmptyBlocks": true,
++    "disallowMixedSpacesAndTabs": true,
++    "disallowSpaceAfterObjectKeys": true,
++    "disallowSpaceAfterPrefixUnaryOperators": ["!", "~", "++", "--", "+", "-"],
++    "disallowSpaceBeforeBinaryOperators": [","],
++    "disallowSpacesInNamedFunctionExpression": {
++        "beforeOpeningRoundBrace": true
++    },
++    "disallowSpacesInsideParentheses": true,
++    "disallowTrailingWhitespace": true,
++    "disallowPaddingNewlinesInBlocks": true,
++    "requireCapitalizedConstructors": true,
++    "requireCommaBeforeLineBreak": true,
++    "requireLineFeedAtFileEnd": true,
++    "requireParenthesesAroundIIFE": true,
++    "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
++    "requireSpaceAfterKeywords": [
++        "if",
++        "else",
++        "for",
++        "while",
++        "do",
++        "switch",
++        "return",
++        "try",
++        "catch",
++        "function"
++    ],
++    "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
++    "requireSpaceBeforeBlockStatements": true,
++    "requireSpacesInAnonymousFunctionExpression": {
++        "beforeOpeningRoundBrace": true,
++        "beforeOpeningCurlyBrace": true
++    },
++    "requireSpacesInFunctionDeclaration": {
++        "beforeOpeningCurlyBrace": true
++    },
++    "validateIndentation": 4,
++    "validateLineBreaks": "LF"
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4df2414fb462e98a7eb8c017182f8b306f8b1778
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++{
++    "esnext": true,
++    "evil": false,
++    "indent": 4,
++    "moz": true,
++    "multistr": true,
++    "sub": true,
++    "trailing": true,
++    "undef": true,
++    "unused": true,
++    "predef": [
++        "addCustomEqualityTester",
++        "afterAll",
++        "afterEach",
++        "ARGV",
++        "beforeAll",
++        "beforeEach",
++        "describe",
++        "expect",
++        "fdescribe",
++        "fit",
++        "imports",
++        "it",
++        "jasmine",
++        "pending",
++        "print",
++        "printerr",
++        "spyOn",
++        "window",
++        "xdescribe",
++        "xit"
++    ]
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3883b7359ac8d90de76f65a803c90737e5e5343
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++---
++dist: focal
++addons:
++  apt:
++    packages:
++      - gjs
++      - meson
++      - npm
++matrix:
++  include:
++    - name: Linter
++      script: |
++        npm install -g eslint &&
++        eslint bin/* src test
++    - name: Unit tests
++      script: |
++        meson _build &&
++        ninja -C _build &&
++        RUN_THOROUGH_TESTS=yes meson test -C _build
++    - name: Installed test
++      script: |
++        meson _build &&
++        ninja -C _build &&
++        sudo ninja -C _build install &&
++        jasmine
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..36a0acc3d57059afa544091221402ae5ea2dd62c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++The MIT License (MIT)
++
++Copyright (c) 2015 Philip Chimento
++
++Permission is hereby granted, free of charge, to any person obtaining a copy
++of this software and associated documentation files (the "Software"), to deal
++in the Software without restriction, including without limitation the rights
++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++copies of the Software, and to permit persons to whom the Software is
++furnished to do so, subject to the following conditions:
++
++The above copyright notice and this permission notice shall be included in all
++copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++SOFTWARE.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ee475af865b8c96bae961f0f25b863b6ea6877fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,82 @@@
++# Release Notes
++
++## 2.6.4 - September 13, 2020
++
++- The internal copy of the Jasmine library has been updated to version 2.6.4, which brings:
++  - Add `toBeNegativeInfinity()`, `toBePositiveInfinity()`, `toHaveBeenCalledBefore()` matchers
++  - Add `spyOnProperty()` for get/set accessors
++  - Add support for ES6 sets to `toContain()` and `toEqual()`
++  - Bug fixes included in 2.6.0, 2.6.1, 2.6.2, 2.6.3 and 2.6.4
++- Thanks to Andy Holmes for contributing.
++
++## 2.5.2 - September 10, 2020
++
++- The internal copy of the Jasmine library has been updated to version 2.5.2, which brings:
++  - Add `toBeGreaterThanOrEqual()` and `toBeLessThanOrEqual()` matchers
++  - Bug fixes included in 2.5.0, 2.5.1 and 2.5.2
++- Thanks to Andy Holmes for contributing.
++
++## 2.4.1 - Sepetember 4, 2020
++
++- The internal copy of the Jasmine library has been updated to version 2.4.1, which brings:
++  - Run jasmine's specs in random order
++  - Add support for returning run details for reporting randomness
++  - Bug fixes included in 2.4.0
++- Thanks to Andy Holmes for contributing.
++
++## 2.3.4 - August 30, 2020
++
++- Fixed a regression in 2.3.0 which caused include paths in the config file to be treated as additional spec paths.
++- The TAP reporter now outputs the test plan at the beginning instead of the end, as it should.
++- The internal copy of the Jasmine library has been updated to version 2.3.4, which brings in the minor bugfixes from 2.3.1, 2.3.2, and 2.3.3 as well.
++- Thanks to Andy Holmes for contributing.
++
++## 2.3.0 - August 25, 2020
++
++- Added a `--debug` command line flag which will run the tests under GDB or the debugger of your choice.
++- Added an `--interpreter` command line flag which allows using a different interpreter than whichever copy of `gjs` is in your path.
++- Fixed several bugs around the loading of spec files.
++- Improved error messages.
++- Jasmine GJS now depends on GJS 1.58.0.
++- The internal copy of the Jasmine library has been updated to 2.3.0, which brings:
++  - `done.fail()` for asynchronous specs.
++  - `toContain()` can be used for finding substrings.
++  - `toThrow()` can be used to check that a particular value was thrown.
++- Thanks to Niv Sardi, Bart Libert and Andy Holmes for contributing.
++
++## 2.2.1 - June 30, 2015
++
++- We now use `/usr/bin/env` to locate jasmine-gjs which allows Jasmine to be used with a development version of GJS. (Thanks to Sam Spilsbury)
++- We don't exit with `System.exit()` on success, because that bypasses the GJS interpreter shutdown actions. (Thanks to Sam Spilsbury)
++- The internal copy of the Jasmine library has been updated to version 2.2.1, which is a minor bugfix release.
++
++## 2.2.0 - May 17, 2015
++
++- You can now specify file patterns to exclude using the `--exclude`
++  command line option.
++  Previously you could only do this via the config file.
++- You can now set environment variables in the config file using the
++  `"environment"` key.
++- When you specify a directory for JUnit reports to be placed in, that
++  directory will now be created if it doesn't already exist.
++- If the argument to `--junit` is not an absolute path, then the path
++  will be resolved relative to the current directory.
++  However, you can now resolve it relative to a different path by
++  setting the environment variable `JASMINE_JUNIT_REPORTS_DIR`.
++- The verbose and TAP reporters now report the reason why a spec has
++  been marked pending, if any reason has been given.
++- The internal copy of the Jasmine library has been updated to version
++  2.2.0, including the following features:
++  - the `toThrowError()` matcher to expect a particular exception
++  - the `jasmine.anything()` object to match anything
++  - the `jasmine.arrayContaining()` object to match an array containing
++    all of the given objects
++  - the `jasmine.stringMatching()` object to match a string that matches
++    the given regular expression or substring
++  - custom matching objects with `asymmetricMatch` methods
++  - per-spec timeouts with an extra argument to `it()`, `beforeEach()`,
++    and `afterEach()`
++
++## 2.1.3 - March 4, 2015
++
++- Initial release.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dfd95ed96c90a4e43fa3cdec88ec0885820f9a5c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,232 @@@
++[![Build Status](https://travis-ci.org/ptomato/jasmine-gjs.png?branch=master)](https://travis-ci.org/ptomato/jasmine-gjs)
++
++# Jasmine for GJS
++
++[Jasmine](https://github.com/jasmine/jasmine) is a BDD (behavior-driven
++development) framework for JavaScript.
++
++## Contents
++
++This module allows you to run Jasmine specs for your GJS code.
++The output will be displayed in your terminal.
++
++## Installation
++
++From Git:
++
++```sh
++git clone https://github.com/ptomato/jasmine-gjs
++cd jasmine-gjs
++meson _build
++ninja -C _build
++sudo ninja -C _build install
++```
++
++From a tarball:
++
++```sh
++tar xJf jasmine-gjs-2.1.3.tar.xz
++cd jasmine-gjs-2.1.3
++meson _build
++ninja -C _build
++sudo ninja -C _build install
++```
++
++## Usage
++
++To run your test suite, pass its directory to the `jasmine` command:
++
++```bash
++jasmine mytestsuitedir
++```
++
++To run an individual spec:
++
++```bash
++jasmine path/to/spec.js
++```
++
++## Options
++
++`--no-color`: Don't output color in the terminal.
++(Opposite of `--color`.)
++
++`--exclude <file>`: Don't run specs that match `file` (which may
++contain `?` and `*` wildcards.)
++This is useful if you pass a directory of specs that also contains
++utility modules or specs that you don't want to run by default.
++You may specify this option more than once with different arguments.
++
++`--verbose`: Output verbose results, formatted similarly to Mocha's
++output.
++(The default output is formatted the same as Jasmine's Node.JS runner's
++output.)
++
++`--tap`: Output according to the
++[Test Anything Protocol](http://testanything.org/).
++This is useful when integrating with Automake (see below.)
++
++`--junit [<file>]`: In addition to the console output, print a JUnit-style
++XML report to `file`.
++If no file is given, the default is `report.xml` in the current working
++directory.
++If you don't specify an absolute path but you do set the environment variable `JASMINE_JUNIT_REPORTS_DIR`, then the report will be placed there instead.
++This allows you to use `$$tst` as the argument to `--junit` in your Makefile to mirror your test directory structure in your report directory.
++
++`--config <file>`: Use `file` as Jasmine's configuration file instead of
++the default `jasmine.json`.
++
++`--no-config`: Don't load a configuration file, even if one is present.
++
++## Configuration file
++
++Maybe you don't want to keep typing the same options every time you run
++your tests.
++In that case, you can create a configuration file called `jasmine.json`.
++Jasmine will look for it in the current working directory by default.
++
++If you configure your test suites in the configuration file, then you
++can start Jasmine simply by running
++
++```bash
++jasmine
++```
++
++The file should be a JSON file.
++You can use the following keys:
++
++`include_paths`: (string or array of strings)
++Prepend these paths to GJS's include paths, in order of priority,
++highest first.
++(The same as specifying `-I` to GJS or defining the `GJS_PATH`
++environment variable.)
++Relative paths are resolved relative to the configuration file's
++location.
++
++`options`: (string or array of strings)
++Use these command-line options for Jasmine by default.
++Options given on the command line will override these in the event of a
++conflict.
++
++`exclude`: (string or array of strings)
++Don't run specs in these files or directories.
++They may contain `*` and `?` as wildcards.
++(The same as specifying `--exclude` on the command line.)
++
++`spec_files`: (string or array of strings)
++Run specs in these files or directories.
++The same as specifying files or directories on the command line.
++If you specify any on the command line, then this option is entirely
++ignored; this is useful for running your entire test suite by default
++but retaining the ability to run just one spec file on the command line.
++Relative paths are resolved relative to the configuration file's
++location.
++
++`environment`: (object with string properties)
++Execute specs with a modified environment.
++Each property of the given object is added as an environment variable.
++If a property's value is `null`, then any existing environment variable
++of that name is unset.
++This is mainly useful if your Javascript code uses a private C library;
++you can add `LD_LIBRARY_PATH` and `GI_TYPELIB_PATH` to `environment` in
++order to expose that library to GJS's GObject introspection repository.
++
++## Integration with Meson
++
++If using Meson, you might want to integrate your test suite into your build process.
++Meson can parse the output of the TAP reporter automatically and display a full report at the end.
++
++Put this code in `meson.build`:
++
++```
++jasmine = find_program('jasmine')
++
++test(test_name, jasmine, args: [test_file, '--tap', '--no-config'],
++    protocol: 'tap')
++```
++
++Where `test_name` and `test_file` are the name of your test and the JS
++script to run, respectively.
++
++## Integration with Autotools
++
++If using autotools, you might want to integrate your test suite into
++your makefiles.
++The TAP reporter produces output that Automake can parse and display
++while the tests are running.
++That way, you have more immediate feedback and can see problems directly
++from your build output.
++
++Put this code in `configure.ac`:
++
++```
++AC_PROG_AWK
++AC_REQUIRE_AUX_FILE([tap-driver.sh])
++```
++
++Then re-run `autogen.sh` or `autoreconf` to install the TAP driver.
++
++Then, put this code in your `Makefile.am`:
++
++```make
++JS_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh
++JS_LOG_DRIVER_FLAGS = --comments
++
++TESTS = path/to/spec1.js path/to/spec2.js
++TEST_EXTENSIONS = .js
++JS_LOG_COMPILER = jasmine
++AM_JS_LOG_FLAGS = --tap --no-config
++```
++
++Don't forget to `EXTRA_DIST` your spec files too.
++Now Jasmine will run your spec files one by one as part of `make check`.
++
++With this configuration, the TAP driver displays all the extra
++diagnostic information about suites starting and finishing, and
++expectation messages in case of failure.
++If you don't want that, remove the `JS_LOG_DRIVER_FLAGS` line.
++
++### A note on extra files
++
++If you use on-disk test fixtures, you should note that someone may be
++building your software with separate source and build trees.
++Notably, Meson does this.
++In that case, you have to make sure that your fixtures can be found both
++when running tests from the source directory and from a separate build
++directory.
++I suggest defining an environment variable in your makefile that tells
++where the fixtures can be found.
++For example, in Jasmine GJS's own tests, this line is in `meson.build`:
++
++```
++test_env = {
++    'SRCDIR': meson.current_source_dir(),
++}
++```
++
++The test code then reads the environment variable like this:
++
++```js
++let envSrcdir = GLib.getenv('SRCDIR');
++const SRCDIR = envSrcdir? envSrcdir + '/' : '';
++
++doSomethingWithFixture(SRCDIR + 'path/to/fixture');
++```
++
++## Support
++
++Please file issues here at
++[GitHub](https://github.com/ptomato/jasmine-gjs/issues).
++
++## Credits
++
++The idea of Jasmine for GJS was first explored by my coworkers Devin
++Ekins and Sam Spilsbury:
++[eos-jasmine](https://github.com/endlessm/eos-jasmine).
++This code, however, was unashamedly cribbed from Pivotal Labs'
++[jasmine-npm](https://github.com/jasmine/jasmine-npm), then expanded
++into what it is now.
++
++Copyright (c) 2015 Philip Chimento.
++This software is licensed under the MIT License &mdash; because Jasmine
++and Jasmine NPM are too.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b2f2bb11c2d0a2044b910a1aff5039f7567727ac
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++#!/usr/bin/env -S gjs -m
++
++/* global jasmineImporter */
++
++import GLib from 'gi://GLib';
++
++const pkgdatadir = GLib.getenv('TEST_PKGDATADIR') ?? '@pkgdatadir@';
++const jasmineMod = GLib.getenv('TEST_JASMINE_MOD') ?? '@jasmine_mod@';
++
++// Create a separate GJS importer object for Jasmine modules, so that Jasmine's
++// modules are not exposed to test code (e.g. client code might have its own
++// Utils module.)
++// This means that all imports within Jasmine must use jasmineImporter rather
++// than imports. That includes imports of Jasmine modules in the tests. It would
++// be better to test a separate copy of Jasmine code, but importing most modules
++// registers a GType, and we cannot register two GTypes with the same name in
++// the same process.
++
++const oldSearchPath = imports.searchPath.slice();  // make a copy
++imports.searchPath.unshift(GLib.path_get_dirname(pkgdatadir));
++globalThis.jasmineImporter = imports[jasmineMod];
++imports.searchPath = oldSearchPath;
++
++const base = `file://${pkgdatadir}`;
++
++const Command = await import(`${base}/command.js`);
++const JasmineBoot = await import(`${base}/jasmineBoot.js`);
++
++// Do not conflict with global "jasmine" object
++const _jasmine = new JasmineBoot.Jasmine();
++_jasmine.installAPI(globalThis);
++
++// Don't put any code after this; the return value is used as the exit code.
++await Command.run(_jasmine, ARGV, 10);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ee57692579de5a7807ebb794d2230a0e130d556a
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,37 @@@
++#!/usr/bin/env -S gjs -m
++
++import GLib from 'gi://GLib';
++import * as System from 'system';
++
++const pkglibexecdir = GLib.getenv('TEST_PKGLIBEXECDIR') ?? '@pkglibexecdir@';
++const pkgdatadir = GLib.getenv('TEST_PKGDATADIR') ?? '@pkgdatadir@';
++
++const runnerPath = `${pkglibexecdir}/jasmine-runner`;
++const base = `file://${pkgdatadir}`;
++
++const Config = await import(`${base}/config.js`);
++const Options = await import(`${base}/options.js`);
++
++const [files, options] = Options.parseOptions(ARGV);
++
++if (options.version) {
++    print('Jasmine @PACKAGE_VERSION@');
++    System.exit(0);
++}
++
++const config = Config.loadConfig(options);
++
++// Launch Jasmine in a subprocess so we can control the environment
++const launcher = Config.prepareLauncher(config, options);
++let args = Config.configToArgs(config, files, options);
++args.unshift(runnerPath);  // argv[0]
++args = Config.wrapArgs(args, config, options);
++const process = launcher.spawnv(args);
++process.wait(null);
++
++// Don't put any code after this; the return value is used as the exit code.
++(function () {
++    if (process.get_if_exited())
++        return process.get_exit_status();
++    return 1;
++})();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..02e243e9b0140c4626e20c7218e7c51fe1c6c1ad
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,52 @@@
++jasmine-gjs (2.6.4-1) unstable; urgency=low
++
++  * Upgrade to 2.6.4
++
++ -- Andy Holmes <andrew.g.r.holmes@gmail.com>  Thu, 10 Sep 2020 21:47:34 -0700
++
++jasmine-gjs (2.5.2-1) unstable; urgency=low
++
++  * Upgrade to 2.5.2
++
++ -- Andy Holmes <andrew.g.r.holmes@gmail.com>  Fri, 04 Sep 2020 19:20:51 -0700
++
++jasmine-gjs (2.4.1-1) unstable; urgency=low
++
++  * Upgrade to 2.4.1
++
++ -- Andy Holmes <andrew.g.r.holmes@gmail.com>  Sat, 29 Aug 2020 19:46:28 -0700
++
++jasmine-gjs (2.3.4-1) unstable; urgency=low
++
++  * Upgrade to 2.3.4
++
++ -- Andy Holmes <andrew.g.r.holmes@gmail.com>  Wed, 26 Aug 2020 16:34:43 -0700
++
++jasmine-gjs (2.3.0-1) unstable; urgency=low
++
++  * Upgrade to 2.3.0
++  * control: Bump GJS requirement to 1.58.0
++  * control, rules: Meson build system
++  * control: Update to modern versions of standards and debhelper-compat
++
++ -- Philip Chimento <philip.chimento@gmail.com>  Tue, 25 Aug 2020 22:19:41 -0700
++
++jasmine-gjs (2.2.1-1) unstable; urgency=low
++
++  * Upgrade to 2.2.1
++
++ -- Philip Chimento <philip.chimento@gmail.com>  Tue, 30 Jun 2015 14:24:39 -0700
++
++jasmine-gjs (2.2.0-1) unstable; urgency=low
++
++  * Upgrade to 2.2.0
++  * copyright: Update copyright year of upstream Jasmine
++  * docs: Add new NEWS.md file
++
++ -- Philip Chimento <philip.chimento@gmail.com>  Mon, 18 May 2015 01:03:37 -0700
++
++jasmine-gjs (2.1.3-1) unstable; urgency=low
++
++  * Initial release
++
++ -- Philip Chimento <philip.chimento@gmail.com>  Sun, 01 Mar 2015 15:25:17 -0800
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..117ba70d921f5f54c41fb52b77ddf065a00f26c8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++Source: jasmine-gjs
++Section: devel
++Priority: optional
++Maintainer: Philip Chimento <philip.chimento@gmail.com>
++Build-Depends: debhelper-compat (= 12),
++               gir1.2-glib-2.0,
++               gjs (>= 1.58.0),
++               meson (>= 0.50.0)
++Standards-Version: 4.5.0
++Homepage: https://github.com/ptomato/jasmine-gjs
++
++Package: jasmine-gjs
++Architecture: all
++Depends: ${misc:Depends},
++         gir1.2-glib-2.0,
++         gjs (>= 1.58.0)
++Description: Behavior-driven development framework for GJS
++ This module allows you to run Jasmine specs for your GJS code. The output will
++ be displayed in your terminal.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d61cab19cd35d467acf2f66a9b4703f6d068486d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
++Upstream-Name: jasmine-gjs
++Source: https://github.com/ptomato/jasmine-gjs
++License: Expat
++
++Files: *
++Copyright: 2015 Philip Chimento <philip.chimento@gmail.com>
++License: Expat
++
++Files: lib/jasmine.js
++Copyright: 2008-2015 Pivotal Labs
++License: Expat
++
++License: Expat
++ Permission is hereby granted, free of charge, to any person obtaining a copy
++ of this software and associated documentation files (the "Software"), to deal
++ in the Software without restriction, including without limitation the rights
++ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ copies of the Software, and to permit persons to whom the Software is
++ furnished to do so, subject to the following conditions:
++ .
++ The above copyright notice and this permission notice shall be included in all
++ copies or substantial portions of the Software.
++ .
++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ SOFTWARE.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dc676dd5a400f8b42bc9d04677e8a32895eb9dd0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++README.md
++NEWS.md
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5897036ba7299681925a5ac1471a42ec12f5f7d9
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,12 @@@
++#!/usr/bin/make -f
++# -*- makefile -*-
++
++# Uncomment this to turn on verbose mode.
++#export DH_VERBOSE=1
++
++%:
++      dh $@
++
++# Print out test log on failure, so that we can diagnose failures on OBS
++override_dh_auto_test:
++      dh_auto_test || (find . -name testlog.txt | xargs cat ; exit 1)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..163aaf8d82b6c54f23c45f32895dbdfdcc27b047
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++3.0 (quilt)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..352b2e97440920d7a02bced41649dfd8621ae663
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,64 @@@
++Name: jasmine-gjs
++Version: 2.6.4
++Release: 1%{?dist}
++Summary: A behavior-driven development framework for GJS
++
++License: MIT
++URL: https://github.com/ptomato/jasmine-gjs
++Source0: http://ptomato.name/downloads/jasmine-gjs-2.6.4.tar.xz
++
++BuildArch: noarch
++BuildRequires: gjs >= 1.58.0
++BuildRequires: gobject-introspection
++BuildRequires: meson >= 0.50.0
++Requires: gjs >= 1.58.0
++Requires: gobject-introspection
++
++%description
++This module allows you to run Jasmine specs for your GJS code. The output will
++be displayed in your terminal.
++
++%prep
++%autosetup
++
++
++%build
++%meson
++%meson_build
++
++
++%install
++%meson_install
++
++
++%check
++%meson_test
++
++
++%files
++%doc README.md
++%doc NEWS.md
++%doc COPYING
++%doc %{_mandir}/man1/jasmine.1.gz
++%{_bindir}/jasmine
++%{_libexecdir}/%{name}/
++%{_datadir}/%{name}/
++
++
++%changelog
++* Fri Sep 10 2020 Andy Holmes <andrew.g.r.holmes@gmail.com> - 2.6.4-1
++- Update to version 2.6.4.
++* Fri Sep 4 2020 Andy Holmes <andrew.g.r.holmes@gmail.com> - 2.5.2-1
++- Update to version 2.5.2.
++* Sat Aug 29 2020 Andy Holmes <andrew.g.r.holmes@gmail.com> - 2.4.1-1
++- Update to version 2.4.1.
++* Wed Aug 26 2020 Andy Holmes <andrew.g.r.holmes@gmail.com> - 2.3.4-1
++- Update to version 2.3.4.
++* Mon Aug 24 2020 Philip Chimento <philip.chimento@gmail.com> - 2.3.0-1
++- Update to version 2.3.0.
++* Tue Jun 30 2015 Philip Chimento <philip.chimento@gmail.com> - 2.2.1-1
++- Update to version 2.2.1.
++* Sun May 17 2015 Philip Chimento <philip.chimento@gmail.com> - 2.2.0-1
++- Update to version 2.2.0.
++* Wed Mar 4 2015 Philip Chimento <philip.chimento@gmail.com> - 2.1.3-1
++- Initial packaging.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..550ff263edf66e70131bfafca473b478714fe936
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++{
++    "exclude": ["test/fixtures/*", "test/focusedSpecIntegrationTest.js"],
++    "spec_files": "test",
++    "options": "--verbose"
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..16f298071815ede7f7b435cf8226f98acddaf79a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,107 @@@
++.\" Copyright 2015 Philip Chimento <philip.chimento@gmail.com>
++.TH JASMINE 1 "March 1, 2015"
++.\" Please adjust this date whenever revising the manpage.
++.SH NAME
++jasmine \- run Jasmine test suites
++.SH SYNOPSIS
++.B jasmine
++.RB [ \-\-help ]
++.RB [ \-\-color ]
++.RB [ \-\-no\-color ]
++.RB [ \-\-config
++.IR file ]
++.RB [ \-\-no\-config ]
++.RB [ \-\-exclude
++.IR file ]
++.RB [ \-\-verbose ]
++.RB [ \-\-tap ]
++.RB [ \-\-junit
++.RI [ file "]] " files " ..."
++.SH DESCRIPTION
++Jasmine is a behavior-driven development framework for the GJS Javascript
++interpreter.
++The
++.B jasmine
++command is a test runner for Jasmine test suites that has several different
++output formats.
++.PP
++The
++.I files
++specified on the command line are imported and all Jasmine specs defined therein
++are executed.
++You may also specify whole directories in
++.IR files ,
++in which case the directories are searched recursively and files ending in
++.I .js
++will be imported.
++.SH OPTIONS
++.TP
++.B \-\-color
++Print output in color, if the chosen output format supports it.
++.TP
++.BI \-\-config " file"
++Use
++.I file
++as the configuration file, instead of
++.IR jasmine.json .
++.TP
++.BI \-\-exclude " file"
++Don't execute specs in
++.I file
++(which may also be a wildcard pattern) even if they are in a directory specified
++on the command line.
++(Don't forget to escape wildcards so the shell doesn't expand them.)
++.TP
++.B \-\-help
++Show summary of options.
++.TP
++.BI \-\-junit " file"
++In addition to the format used to report results to the console (default,
++.BR \-\-verbose ,
++or
++.BR \-\-tap ,)
++output test results to a JUnit-style XML file to
++.IR file ,
++suitable for integration with Jenkins.
++If
++.I file
++is not given, output to
++.I report.xml
++in the current directory.
++.TP
++.B \-\-no\-color
++Do not print output in color, even if the chosen output format supports it.
++.TP
++.B \-\-no\-config
++Don't use a configuration file, even if one is present.
++.TP
++.B \-\-tap
++Report results with the TAP (Test Anything Protocol) reporter, suitable for
++integration with Automake.
++.TP
++.B \-\-verbose
++Report results with the verbose reporter, similar to Mocha's default reporter.
++.SH EXIT STATUS
++The
++.B jasmine
++utility exits with 0 on success, or with 1 if any tests failed or an internal
++error occurred.
++.SH ENVIRONMENT
++The JASMINE_JUNIT_REPORTS_DIR environment variable controls where JUnit-style
++XML reports are placed, if a relative path is passed to
++.B \-\-junit
++on the command line.
++.PP
++The JASMINE_UNINSTALLED environment variable can be used for debugging Jasmine.
++It is not recommended to set this variable during normal use.
++.SH FILES
++By default, Jasmine reads from a configuration file called
++.I jasmine.json
++in the current directory, if such a file exists.
++This can be influenced with the
++.B \-\-config
++and
++.B \-\-no\-config
++options.
++.SH BUGS
++Report bugs at https://github.com/ptomato/jasmine-gjs/issues on GitHub.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..007712b255bfd3fa9309950887f59956fd2670a5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10116 @@@
++/* jscs:disable */
++/*
++Copyright (c) 2008-2021 Pivotal Labs
++
++Permission is hereby granted, free of charge, to any person obtaining
++a copy of this software and associated documentation files (the
++"Software"), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be
++included in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++*/
++// eslint-disable-next-line no-unused-vars
++var getJasmineRequireObj = (function(jasmineGlobal) {
++  var jasmineRequire;
++
++  if (
++    typeof module !== 'undefined' &&
++    module.exports &&
++    typeof exports !== 'undefined'
++  ) {
++    if (typeof global !== 'undefined') {
++      jasmineGlobal = global;
++    } else {
++      jasmineGlobal = {};
++    }
++    jasmineRequire = exports;
++  } else {
++    if (
++      typeof window !== 'undefined' &&
++      typeof window.toString === 'function' &&
++      window.toString() === '[object GjsGlobal]'
++    ) {
++      jasmineGlobal = window;
++    }
++    jasmineRequire = jasmineGlobal.jasmineRequire = {};
++  }
++
++  function getJasmineRequire() {
++    return jasmineRequire;
++  }
++
++  getJasmineRequire().core = function(jRequire) {
++    var j$ = {};
++
++    jRequire.base(j$, jasmineGlobal);
++    j$.util = jRequire.util(j$);
++    j$.errors = jRequire.errors();
++    j$.formatErrorMsg = jRequire.formatErrorMsg();
++    j$.Any = jRequire.Any(j$);
++    j$.Anything = jRequire.Anything(j$);
++    j$.CallTracker = jRequire.CallTracker(j$);
++    j$.MockDate = jRequire.MockDate();
++    j$.getClearStack = jRequire.clearStack(j$);
++    j$.Clock = jRequire.Clock();
++    j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
++    j$.Env = jRequire.Env(j$);
++    j$.StackTrace = jRequire.StackTrace(j$);
++    j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
++    j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
++    j$.Expector = jRequire.Expector(j$);
++    j$.Expectation = jRequire.Expectation(j$);
++    j$.buildExpectationResult = jRequire.buildExpectationResult(j$);
++    j$.JsApiReporter = jRequire.JsApiReporter(j$);
++    j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim(
++      j$
++    );
++    j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$);
++    j$.pp = j$.makePrettyPrinter();
++    j$.MatchersUtil = jRequire.MatchersUtil(j$);
++    j$.matchersUtil = new j$.MatchersUtil({
++      customTesters: [],
++      pp: j$.pp
++    });
++
++    j$.ObjectContaining = jRequire.ObjectContaining(j$);
++    j$.ArrayContaining = jRequire.ArrayContaining(j$);
++    j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
++    j$.MapContaining = jRequire.MapContaining(j$);
++    j$.SetContaining = jRequire.SetContaining(j$);
++    j$.QueueRunner = jRequire.QueueRunner(j$);
++    j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
++    j$.Spec = jRequire.Spec(j$);
++    j$.Spy = jRequire.Spy(j$);
++    j$.SpyFactory = jRequire.SpyFactory(j$);
++    j$.SpyRegistry = jRequire.SpyRegistry(j$);
++    j$.SpyStrategy = jRequire.SpyStrategy(j$);
++    j$.StringMatching = jRequire.StringMatching(j$);
++    j$.StringContaining = jRequire.StringContaining(j$);
++    j$.UserContext = jRequire.UserContext(j$);
++    j$.Suite = jRequire.Suite(j$);
++    j$.Timer = jRequire.Timer();
++    j$.TreeProcessor = jRequire.TreeProcessor();
++    j$.version = jRequire.version();
++    j$.Order = jRequire.Order();
++    j$.DiffBuilder = jRequire.DiffBuilder(j$);
++    j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
++    j$.ObjectPath = jRequire.ObjectPath(j$);
++    j$.MismatchTree = jRequire.MismatchTree(j$);
++    j$.GlobalErrors = jRequire.GlobalErrors(j$);
++
++    j$.Truthy = jRequire.Truthy(j$);
++    j$.Falsy = jRequire.Falsy(j$);
++    j$.Empty = jRequire.Empty(j$);
++    j$.NotEmpty = jRequire.NotEmpty(j$);
++
++    j$.matchers = jRequire.requireMatchers(jRequire, j$);
++    j$.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$);
++
++    return j$;
++  };
++
++  return getJasmineRequire;
++})(this);
++
++getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
++  var availableMatchers = [
++      'nothing',
++      'toBe',
++      'toBeCloseTo',
++      'toBeDefined',
++      'toBeInstanceOf',
++      'toBeFalse',
++      'toBeFalsy',
++      'toBeGreaterThan',
++      'toBeGreaterThanOrEqual',
++      'toBeLessThan',
++      'toBeLessThanOrEqual',
++      'toBeNaN',
++      'toBeNegativeInfinity',
++      'toBeNull',
++      'toBePositiveInfinity',
++      'toBeTrue',
++      'toBeTruthy',
++      'toBeUndefined',
++      'toContain',
++      'toEqual',
++      'toHaveSize',
++      'toHaveBeenCalled',
++      'toHaveBeenCalledBefore',
++      'toHaveBeenCalledOnceWith',
++      'toHaveBeenCalledTimes',
++      'toHaveBeenCalledWith',
++      'toHaveClass',
++      'toMatch',
++      'toThrow',
++      'toThrowError',
++      'toThrowMatching'
++    ],
++    matchers = {};
++
++  for (var i = 0; i < availableMatchers.length; i++) {
++    var name = availableMatchers[i];
++    matchers[name] = jRequire[name](j$);
++  }
++
++  return matchers;
++};
++
++getJasmineRequireObj().base = function(j$, jasmineGlobal) {
++  j$.unimplementedMethod_ = function() {
++    throw new Error('unimplemented method');
++  };
++
++  /**
++   * Maximum object depth the pretty printer will print to.
++   * Set this to a lower value to speed up pretty printing if you have large objects.
++   * @name jasmine.MAX_PRETTY_PRINT_DEPTH
++   * @default 8
++   * @since 1.3.0
++   */
++  j$.MAX_PRETTY_PRINT_DEPTH = 8;
++  /**
++   * Maximum number of array elements to display when pretty printing objects.
++   * This will also limit the number of keys and values displayed for an object.
++   * Elements past this number will be ellipised.
++   * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
++   * @default 50
++   * @since 2.7.0
++   */
++  j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
++  /**
++   * Maximum number of characters to display when pretty printing objects.
++   * Characters past this number will be ellipised.
++   * @name jasmine.MAX_PRETTY_PRINT_CHARS
++   * @default 100
++   * @since 2.9.0
++   */
++  j$.MAX_PRETTY_PRINT_CHARS = 1000;
++  /**
++   * Default number of milliseconds Jasmine will wait for an asynchronous spec,
++   * before, or after function to complete. This can be overridden on a case by
++   * case basis by passing a time limit as the third argument to {@link it},
++   * {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or
++   * {@link afterAll}. The value must be no greater than the largest number of
++   * milliseconds supported by setTimeout, which is usually 2147483647.
++   *
++   * While debugging tests, you may want to set this to a large number (or pass
++   * a large number to one of the functions mentioned above) so that Jasmine
++   * does not move on to after functions or the next spec while you're debugging.
++   * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
++   * @default 5000
++   * @since 1.3.0
++   */
++  var DEFAULT_TIMEOUT_INTERVAL = 5000;
++  Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', {
++    get: function() {
++      return DEFAULT_TIMEOUT_INTERVAL;
++    },
++    set: function(newValue) {
++      j$.util.validateTimeout(newValue, 'jasmine.DEFAULT_TIMEOUT_INTERVAL');
++      DEFAULT_TIMEOUT_INTERVAL = newValue;
++    }
++  });
++
++  j$.getGlobal = function() {
++    return jasmineGlobal;
++  };
++
++  /**
++   * Get the currently booted Jasmine Environment.
++   *
++   * @name jasmine.getEnv
++   * @since 1.3.0
++   * @function
++   * @return {Env}
++   */
++  j$.getEnv = function(options) {
++    var env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options));
++    //jasmine. singletons in here (setTimeout blah blah).
++    return env;
++  };
++
++  j$.isArray_ = function(value) {
++    return j$.isA_('Array', value);
++  };
++
++  j$.isObject_ = function(value) {
++    return (
++      !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value)
++    );
++  };
++
++  j$.isString_ = function(value) {
++    return j$.isA_('String', value);
++  };
++
++  j$.isNumber_ = function(value) {
++    return j$.isA_('Number', value);
++  };
++
++  j$.isFunction_ = function(value) {
++    return j$.isA_('Function', value);
++  };
++
++  j$.isAsyncFunction_ = function(value) {
++    return j$.isA_('AsyncFunction', value);
++  };
++
++  j$.isGeneratorFunction_ = function(value) {
++    return j$.isA_('GeneratorFunction', value);
++  };
++
++  j$.isTypedArray_ = function(value) {
++    return (
++      j$.isA_('Float32Array', value) ||
++      j$.isA_('Float64Array', value) ||
++      j$.isA_('Int16Array', value) ||
++      j$.isA_('Int32Array', value) ||
++      j$.isA_('Int8Array', value) ||
++      j$.isA_('Uint16Array', value) ||
++      j$.isA_('Uint32Array', value) ||
++      j$.isA_('Uint8Array', value) ||
++      j$.isA_('Uint8ClampedArray', value)
++    );
++  };
++
++  j$.isA_ = function(typeName, value) {
++    return j$.getType_(value) === '[object ' + typeName + ']';
++  };
++
++  j$.isError_ = function(value) {
++    if (!value) {
++      return false;
++    }
++
++    if (value instanceof Error) {
++      return true;
++    }
++    if (
++      typeof window !== 'undefined' &&
++      typeof window.trustedTypes !== 'undefined'
++    ) {
++      return (
++        typeof value.stack === 'string' && typeof value.message === 'string'
++      );
++    }
++    if (value && value.constructor && value.constructor.constructor) {
++      var valueGlobal = value.constructor.constructor('return this');
++      if (j$.isFunction_(valueGlobal)) {
++        valueGlobal = valueGlobal();
++      }
++
++      if (valueGlobal.Error && value instanceof valueGlobal.Error) {
++        return true;
++      }
++    }
++    return false;
++  };
++
++  j$.isAsymmetricEqualityTester_ = function(obj) {
++    return obj?.asymmetricMatch ? j$.isA_('Function', obj.asymmetricMatch) : false;
++  };
++
++  j$.getType_ = function(value) {
++    return Object.prototype.toString.apply(value);
++  };
++
++  j$.isDomNode = function(obj) {
++    // Node is a function, because constructors
++    return typeof jasmineGlobal.Node !== 'undefined'
++      ? obj instanceof jasmineGlobal.Node
++      : obj !== null &&
++          typeof obj === 'object' &&
++          typeof obj.nodeType === 'number' &&
++          typeof obj.nodeName === 'string';
++    // return obj.nodeType > 0;
++  };
++
++  j$.isMap = function(obj) {
++    return (
++      obj !== null &&
++      typeof obj !== 'undefined' &&
++      typeof jasmineGlobal.Map !== 'undefined' &&
++      obj.constructor === jasmineGlobal.Map
++    );
++  };
++
++  j$.isSet = function(obj) {
++    return (
++      obj !== null &&
++      typeof obj !== 'undefined' &&
++      typeof jasmineGlobal.Set !== 'undefined' &&
++      obj.constructor === jasmineGlobal.Set
++    );
++  };
++
++  j$.isWeakMap = function(obj) {
++    return (
++      obj !== null &&
++      typeof obj !== 'undefined' &&
++      typeof jasmineGlobal.WeakMap !== 'undefined' &&
++      obj.constructor === jasmineGlobal.WeakMap
++    );
++  };
++
++  j$.isURL = function(obj) {
++    return (
++      obj !== null &&
++      typeof obj !== 'undefined' &&
++      typeof jasmineGlobal.URL !== 'undefined' &&
++      obj.constructor === jasmineGlobal.URL
++    );
++  };
++
++  j$.isDataView = function(obj) {
++    return (
++      obj !== null &&
++      typeof obj !== 'undefined' &&
++      typeof jasmineGlobal.DataView !== 'undefined' &&
++      obj.constructor === jasmineGlobal.DataView
++    );
++  };
++
++  j$.isPromise = function(obj) {
++    return (
++      typeof jasmineGlobal.Promise !== 'undefined' &&
++      !!obj &&
++      obj.constructor === jasmineGlobal.Promise
++    );
++  };
++
++  j$.isPromiseLike = function(obj) {
++    return !!obj && j$.isFunction_(obj.then);
++  };
++
++  j$.fnNameFor = function(func) {
++    if (func.name) {
++      return func.name;
++    }
++
++    var matches =
++      func.toString().match(/^\s*function\s*(\w+)\s*\(/) ||
++      func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/);
++
++    return matches ? matches[1] : '<anonymous>';
++  };
++
++  j$.isPending_ = function(promise) {
++    var sentinel = {};
++    // eslint-disable-next-line compat/compat
++    return Promise.race([promise, Promise.resolve(sentinel)]).then(
++      function(result) {
++        return result === sentinel;
++      },
++      function() {
++        return false;
++      }
++    );
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared is an instance of the specified class/constructor.
++   * @name jasmine.any
++   * @since 1.3.0
++   * @function
++   * @param {Constructor} clazz - The constructor to check against.
++   */
++  j$.any = function(clazz) {
++    return new j$.Any(clazz);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared is not `null` and not `undefined`.
++   * @name jasmine.anything
++   * @since 2.2.0
++   * @function
++   */
++  j$.anything = function() {
++    return new j$.Anything();
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared is `true` or anything truthy.
++   * @name jasmine.truthy
++   * @since 3.1.0
++   * @function
++   */
++  j$.truthy = function() {
++    return new j$.Truthy();
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared is  `null`, `undefined`, `0`, `false` or anything falsey.
++   * @name jasmine.falsy
++   * @since 3.1.0
++   * @function
++   */
++  j$.falsy = function() {
++    return new j$.Falsy();
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared is empty.
++   * @name jasmine.empty
++   * @since 3.1.0
++   * @function
++   */
++  j$.empty = function() {
++    return new j$.Empty();
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared is not empty.
++   * @name jasmine.notEmpty
++   * @since 3.1.0
++   * @function
++   */
++  j$.notEmpty = function() {
++    return new j$.NotEmpty();
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value being compared contains at least the keys and values.
++   * @name jasmine.objectContaining
++   * @since 1.3.0
++   * @function
++   * @param {Object} sample - The subset of properties that _must_ be in the actual.
++   */
++  j$.objectContaining = function(sample) {
++    return new j$.ObjectContaining(sample);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
++   * @name jasmine.stringMatching
++   * @since 2.2.0
++   * @function
++   * @param {RegExp|String} expected
++   */
++  j$.stringMatching = function(expected) {
++    return new j$.StringMatching(expected);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value is a `String` that contains the specified `String`.
++   * @name jasmine.stringContaining
++   * @since 3.10.0
++   * @function
++   * @param {String} expected
++   */
++  j$.stringContaining = function(expected) {
++    return new j$.StringContaining(expected);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
++   * @name jasmine.arrayContaining
++   * @since 2.2.0
++   * @function
++   * @param {Array} sample
++   */
++  j$.arrayContaining = function(sample) {
++    return new j$.ArrayContaining(sample);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
++   * @name jasmine.arrayWithExactContents
++   * @since 2.8.0
++   * @function
++   * @param {Array} sample
++   */
++  j$.arrayWithExactContents = function(sample) {
++    return new j$.ArrayWithExactContents(sample);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if every key/value pair in the sample passes the deep equality comparison
++   * with at least one key/value pair in the actual value being compared
++   * @name jasmine.mapContaining
++   * @since 3.5.0
++   * @function
++   * @param {Map} sample - The subset of items that _must_ be in the actual.
++   */
++  j$.mapContaining = function(sample) {
++    return new j$.MapContaining(sample);
++  };
++
++  /**
++   * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
++   * that will succeed if every item in the sample passes the deep equality comparison
++   * with at least one item in the actual value being compared
++   * @name jasmine.setContaining
++   * @since 3.5.0
++   * @function
++   * @param {Set} sample - The subset of items that _must_ be in the actual.
++   */
++  j$.setContaining = function(sample) {
++    return new j$.SetContaining(sample);
++  };
++
++  /**
++   * Determines whether the provided function is a Jasmine spy.
++   * @name jasmine.isSpy
++   * @since 2.0.0
++   * @function
++   * @param {Function} putativeSpy - The function to check.
++   * @return {Boolean}
++   */
++  j$.isSpy = function(putativeSpy) {
++    if (!putativeSpy || !putativeSpy.and) {
++      return false;
++    }
++    return (
++      putativeSpy.and instanceof j$.SpyStrategy &&
++      putativeSpy.calls instanceof j$.CallTracker
++    );
++  };
++};
++
++getJasmineRequireObj().util = function(j$) {
++  var util = {};
++
++  util.inherit = function(childClass, parentClass) {
++    var Subclass = function() {};
++    Subclass.prototype = parentClass.prototype;
++    childClass.prototype = new Subclass();
++  };
++
++  util.argsToArray = function(args) {
++    var arrayOfArgs = [];
++    for (var i = 0; i < args.length; i++) {
++      arrayOfArgs.push(args[i]);
++    }
++    return arrayOfArgs;
++  };
++
++  util.isUndefined = function(obj) {
++    return obj === void 0;
++  };
++
++  util.arrayContains = function(array, search) {
++    var i = array.length;
++    while (i--) {
++      if (array[i] === search) {
++        return true;
++      }
++    }
++    return false;
++  };
++
++  util.clone = function(obj) {
++    if (Object.prototype.toString.apply(obj) === '[object Array]') {
++      return obj.slice();
++    }
++
++    var cloned = {};
++    for (var prop in obj) {
++      if (obj.hasOwnProperty(prop)) {
++        cloned[prop] = obj[prop];
++      }
++    }
++
++    return cloned;
++  };
++
++  util.cloneArgs = function(args) {
++    var clonedArgs = [];
++    var argsAsArray = j$.util.argsToArray(args);
++    for (var i = 0; i < argsAsArray.length; i++) {
++      var str = Object.prototype.toString.apply(argsAsArray[i]),
++        primitives = /^\[object (Boolean|String|RegExp|Number)/;
++
++      // All falsey values are either primitives, `null`, or `undefined.
++      if (!argsAsArray[i] || str.match(primitives)) {
++        clonedArgs.push(argsAsArray[i]);
++      } else {
++        clonedArgs.push(j$.util.clone(argsAsArray[i]));
++      }
++    }
++    return clonedArgs;
++  };
++
++  util.getPropertyDescriptor = function(obj, methodName) {
++    var descriptor,
++      proto = obj;
++
++    do {
++      descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
++      proto = Object.getPrototypeOf(proto);
++    } while (!descriptor && proto);
++
++    return descriptor;
++  };
++
++  util.objectDifference = function(obj, toRemove) {
++    var diff = {};
++
++    for (var key in obj) {
++      if (util.has(obj, key) && !util.has(toRemove, key)) {
++        diff[key] = obj[key];
++      }
++    }
++
++    return diff;
++  };
++
++  util.has = function(obj, key) {
++    return Object.prototype.hasOwnProperty.call(obj, key);
++  };
++
++  util.errorWithStack = function errorWithStack() {
++    // Don't throw and catch if we don't have to, because it makes it harder
++    // for users to debug their code with exception breakpoints.
++    var error = new Error();
++
++    if (error.stack) {
++      return error;
++    }
++
++    // But some browsers (e.g. Phantom) only provide a stack trace if we throw.
++    try {
++      throw new Error();
++    } catch (e) {
++      return e;
++    }
++  };
++
++  function callerFile() {
++    var trace = new j$.StackTrace(util.errorWithStack());
++    return trace.frames[2].file;
++  }
++
++  util.jasmineFile = (function() {
++    var result;
++
++    return function() {
++      if (!result) {
++        result = callerFile();
++      }
++
++      return result;
++    };
++  })();
++
++  function StopIteration() {}
++  StopIteration.prototype = Object.create(Error.prototype);
++  StopIteration.prototype.constructor = StopIteration;
++
++  // useful for maps and sets since `forEach` is the only IE11-compatible way to iterate them
++  util.forEachBreakable = function(iterable, iteratee) {
++    function breakLoop() {
++      throw new StopIteration();
++    }
++
++    try {
++      iterable.forEach(function(value, key) {
++        iteratee(breakLoop, value, key, iterable);
++      });
++    } catch (error) {
++      if (!(error instanceof StopIteration)) throw error;
++    }
++  };
++
++  util.validateTimeout = function(timeout, msgPrefix) {
++    // Timeouts are implemented with setTimeout, which only supports a limited
++    // range of values. The limit is unspecified, as is the behavior when it's
++    // exceeded. But on all currently supported JS runtimes, setTimeout calls
++    // the callback immediately when the timeout is greater than 2147483647
++    // (the maximum value of a signed 32 bit integer).
++    var max = 2147483647;
++
++    if (timeout > max) {
++      throw new Error(
++        (msgPrefix || 'Timeout value') + ' cannot be greater than ' + max
++      );
++    }
++  };
++
++  return util;
++};
++
++getJasmineRequireObj().Spec = function(j$) {
++  /**
++   * @interface Spec
++   * @see Configuration#specFilter
++   * @since 2.0.0
++   */
++  function Spec(attrs) {
++    this.expectationFactory = attrs.expectationFactory;
++    this.asyncExpectationFactory = attrs.asyncExpectationFactory;
++    this.resultCallback = attrs.resultCallback || function() {};
++    /**
++     * The unique ID of this spec.
++     * @name Spec#id
++     * @readonly
++     * @type {string}
++     * @since 2.0.0
++     */
++    this.id = attrs.id;
++    /**
++     * The description passed to the {@link it} that created this spec.
++     * @name Spec#description
++     * @readonly
++     * @type {string}
++     * @since 2.0.0
++     */
++    this.description = attrs.description || '';
++    this.queueableFn = attrs.queueableFn;
++    this.beforeAndAfterFns =
++      attrs.beforeAndAfterFns ||
++      function() {
++        return { befores: [], afters: [] };
++      };
++    this.userContext =
++      attrs.userContext ||
++      function() {
++        return {};
++      };
++    this.onStart = attrs.onStart || function() {};
++    this.autoCleanClosures =
++      attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
++    this.getSpecName =
++      attrs.getSpecName ||
++      function() {
++        return '';
++      };
++    this.expectationResultFactory =
++      attrs.expectationResultFactory || function() {};
++    this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
++    this.catchingExceptions =
++      attrs.catchingExceptions ||
++      function() {
++        return true;
++      };
++    this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
++    this.timer = attrs.timer || new j$.Timer();
++
++    if (!this.queueableFn.fn) {
++      this.exclude();
++    }
++
++    /**
++     * @typedef SpecResult
++     * @property {Int} id - The unique id of this spec.
++     * @property {String} description - The description passed to the {@link it} that created this spec.
++     * @property {String} fullName - The full description including all ancestors of this spec.
++     * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
++     * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
++     * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
++     * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
++     * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
++     * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
++     * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
++     * @since 2.0.0
++x     */
++    this.result = {
++      id: this.id,
++      description: this.description,
++      fullName: this.getFullName(),
++      failedExpectations: [],
++      passedExpectations: [],
++      deprecationWarnings: [],
++      pendingReason: '',
++      duration: null,
++      properties: null
++    };
++  }
++
++  Spec.prototype.addExpectationResult = function(passed, data, isError) {
++    var expectationResult = this.expectationResultFactory(data);
++    if (passed) {
++      this.result.passedExpectations.push(expectationResult);
++    } else {
++      this.result.failedExpectations.push(expectationResult);
++
++      if (this.throwOnExpectationFailure && !isError) {
++        throw new j$.errors.ExpectationFailed();
++      }
++    }
++  };
++
++  Spec.prototype.setSpecProperty = function(key, value) {
++    this.result.properties = this.result.properties || {};
++    this.result.properties[key] = value;
++  };
++
++  Spec.prototype.expect = function(actual) {
++    return this.expectationFactory(actual, this);
++  };
++
++  Spec.prototype.expectAsync = function(actual) {
++    return this.asyncExpectationFactory(actual, this);
++  };
++
++  Spec.prototype.execute = function(onComplete, excluded, failSpecWithNoExp) {
++    var self = this;
++
++    var onStart = {
++      fn: function(done) {
++        self.timer.start();
++        self.onStart(self, done);
++      }
++    };
++
++    var complete = {
++      fn: function(done) {
++        if (self.autoCleanClosures) {
++          self.queueableFn.fn = null;
++        }
++        self.result.status = self.status(excluded, failSpecWithNoExp);
++        self.result.duration = self.timer.elapsed();
++        self.resultCallback(self.result, done);
++      }
++    };
++
++    var fns = this.beforeAndAfterFns();
++    var regularFns = fns.befores.concat(this.queueableFn);
++
++    var runnerConfig = {
++      isLeaf: true,
++      queueableFns: regularFns,
++      cleanupFns: fns.afters,
++      onException: function() {
++        self.onException.apply(self, arguments);
++      },
++      onComplete: function() {
++        onComplete(
++          self.result.status === 'failed' &&
++            new j$.StopExecutionError('spec failed')
++        );
++      },
++      userContext: this.userContext()
++    };
++
++    if (this.markedPending || excluded === true) {
++      runnerConfig.queueableFns = [];
++      runnerConfig.cleanupFns = [];
++    }
++
++    runnerConfig.queueableFns.unshift(onStart);
++    runnerConfig.cleanupFns.push(complete);
++
++    this.queueRunnerFactory(runnerConfig);
++  };
++
++  Spec.prototype.reset = function() {
++    /**
++     * @typedef SpecResult
++     * @property {Int} id - The unique id of this spec.
++     * @property {String} description - The description passed to the {@link it} that created this spec.
++     * @property {String} fullName - The full description including all ancestors of this spec.
++     * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
++     * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
++     * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
++     * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
++     * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
++     * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
++     * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
++     * @since 2.0.0
++     */
++    this.result = {
++      id: this.id,
++      description: this.description,
++      fullName: this.getFullName(),
++      failedExpectations: [],
++      passedExpectations: [],
++      deprecationWarnings: [],
++      pendingReason: this.excludeMessage,
++      duration: null,
++      properties: null,
++      trace: null
++    };
++    this.markedPending = this.markedExcluding;
++  };
++
++  Spec.prototype.onException = function onException(e) {
++    if (Spec.isPendingSpecException(e)) {
++      this.pend(extractCustomPendingMessage(e));
++      return;
++    }
++
++    if (e instanceof j$.errors.ExpectationFailed) {
++      return;
++    }
++
++    this.addExpectationResult(
++      false,
++      {
++        matcherName: '',
++        passed: false,
++        expected: '',
++        actual: '',
++        error: e
++      },
++      true
++    );
++  };
++
++  /*
++   * Marks state as pending
++   * @param {string} [message] An optional reason message
++   */
++  Spec.prototype.pend = function(message) {
++    this.markedPending = true;
++    if (message) {
++      this.result.pendingReason = message;
++    }
++  };
++
++  /*
++   * Like {@link Spec#pend}, but pending state will survive {@link Spec#reset}
++   * Useful for fit, xit, where pending state remains.
++   * @param {string} [message] An optional reason message
++   */
++  Spec.prototype.exclude = function(message) {
++    this.markedExcluding = true;
++    if (this.message) {
++      this.excludeMessage = message;
++    }
++    this.pend(message);
++  };
++
++  Spec.prototype.getResult = function() {
++    this.result.status = this.status();
++    return this.result;
++  };
++
++  Spec.prototype.status = function(excluded, failSpecWithNoExpectations) {
++    if (excluded === true) {
++      return 'excluded';
++    }
++
++    if (this.markedPending) {
++      return 'pending';
++    }
++
++    if (
++      this.result.failedExpectations.length > 0 ||
++      (failSpecWithNoExpectations &&
++        this.result.failedExpectations.length +
++          this.result.passedExpectations.length ===
++          0)
++    ) {
++      return 'failed';
++    }
++
++    return 'passed';
++  };
++
++  /**
++   * The full description including all ancestors of this spec.
++   * @name Spec#getFullName
++   * @function
++   * @returns {string}
++   * @since 2.0.0
++   */
++  Spec.prototype.getFullName = function() {
++    return this.getSpecName(this);
++  };
++
++  Spec.prototype.addDeprecationWarning = function(deprecation) {
++    if (typeof deprecation === 'string') {
++      deprecation = { message: deprecation };
++    }
++    this.result.deprecationWarnings.push(
++      this.expectationResultFactory(deprecation)
++    );
++  };
++
++  var extractCustomPendingMessage = function(e) {
++    var fullMessage = e.toString(),
++      boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
++      boilerplateEnd =
++        boilerplateStart + Spec.pendingSpecExceptionMessage.length;
++
++    return fullMessage.substr(boilerplateEnd);
++  };
++
++  Spec.pendingSpecExceptionMessage = '=> marked Pending';
++
++  Spec.isPendingSpecException = function(e) {
++    return !!(
++      e &&
++      e.toString &&
++      e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1
++    );
++  };
++
++  return Spec;
++};
++
++if (typeof window == void 0 && typeof exports == 'object') {
++  /* globals exports */
++  exports.Spec = jasmineRequire.Spec;
++}
++
++/*jshint bitwise: false*/
++
++getJasmineRequireObj().Order = function() {
++  function Order(options) {
++    this.random = 'random' in options ? options.random : true;
++    var seed = (this.seed = options.seed || generateSeed());
++    this.sort = this.random ? randomOrder : naturalOrder;
++
++    function naturalOrder(items) {
++      return items;
++    }
++
++    function randomOrder(items) {
++      var copy = items.slice();
++      copy.sort(function(a, b) {
++        return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id);
++      });
++      return copy;
++    }
++
++    function generateSeed() {
++      return String(Math.random()).slice(-5);
++    }
++
++    // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
++    // used to get a different output when the key changes slightly.
++    // We use your return to sort the children randomly in a consistent way when
++    // used in conjunction with a seed
++
++    function jenkinsHash(key) {
++      var hash, i;
++      for (hash = i = 0; i < key.length; ++i) {
++        hash += key.charCodeAt(i);
++        hash += hash << 10;
++        hash ^= hash >> 6;
++      }
++      hash += hash << 3;
++      hash ^= hash >> 11;
++      hash += hash << 15;
++      return hash;
++    }
++  }
++
++  return Order;
++};
++
++getJasmineRequireObj().Env = function(j$) {
++  /**
++   * @class Env
++   * @since 2.0.0
++   * @classdesc The Jasmine environment.<br>
++   * _Note:_ Do not construct this directly. You can obtain the Env instance by
++   * calling {@link jasmine.getEnv}.
++   * @hideconstructor
++   */
++  function Env(options) {
++    options = options || {};
++
++    var self = this;
++    var global = options.global || j$.getGlobal();
++    var customPromise;
++
++    var totalSpecsDefined = 0;
++
++    var realSetTimeout = global.setTimeout;
++    var realClearTimeout = global.clearTimeout;
++    var clearStack = j$.getClearStack(global);
++    this.clock = new j$.Clock(
++      global,
++      function() {
++        return new j$.DelayedFunctionScheduler();
++      },
++      new j$.MockDate(global)
++    );
++
++    var runnableResources = {};
++
++    var currentSpec = null;
++    var currentlyExecutingSuites = [];
++    var currentDeclarationSuite = null;
++    var hasFailures = false;
++
++    /**
++     * This represents the available options to configure Jasmine.
++     * Options that are not provided will use their default values.
++     * @see Env#configure
++     * @interface Configuration
++     * @since 3.3.0
++     */
++    var config = {
++      /**
++       * Whether to randomize spec execution order
++       * @name Configuration#random
++       * @since 3.3.0
++       * @type Boolean
++       * @default true
++       */
++      random: true,
++      /**
++       * Seed to use as the basis of randomization.
++       * Null causes the seed to be determined randomly at the start of execution.
++       * @name Configuration#seed
++       * @since 3.3.0
++       * @type (number|string)
++       * @default null
++       */
++      seed: null,
++      /**
++       * Whether to stop execution of the suite after the first spec failure
++       * @name Configuration#failFast
++       * @since 3.3.0
++       * @type Boolean
++       * @default false
++       * @deprecated Use the `stopOnSpecFailure` config property instead.
++       */
++      failFast: false,
++      /**
++       * Whether to stop execution of the suite after the first spec failure
++       * @name Configuration#stopOnSpecFailure
++       * @since 3.9.0
++       * @type Boolean
++       * @default false
++       */
++      stopOnSpecFailure: false,
++      /**
++       * Whether to fail the spec if it ran no expectations. By default
++       * a spec that ran no expectations is reported as passed. Setting this
++       * to true will report such spec as a failure.
++       * @name Configuration#failSpecWithNoExpectations
++       * @since 3.5.0
++       * @type Boolean
++       * @default false
++       */
++      failSpecWithNoExpectations: false,
++      /**
++       * Whether to cause specs to only have one expectation failure.
++       * @name Configuration#oneFailurePerSpec
++       * @since 3.3.0
++       * @type Boolean
++       * @default false
++       * @deprecated Use the `stopSpecOnExpectationFailure` config property instead.
++       */
++      oneFailurePerSpec: false,
++      /**
++       * Whether to cause specs to only have one expectation failure.
++       * @name Configuration#stopSpecOnExpectationFailure
++       * @since 3.3.0
++       * @type Boolean
++       * @default false
++       */
++      stopSpecOnExpectationFailure: false,
++      /**
++       * A function that takes a spec and returns true if it should be executed
++       * or false if it should be skipped.
++       * @callback SpecFilter
++       * @param {Spec} spec - The spec that the filter is being applied to.
++       * @return boolean
++       */
++      /**
++       * Function to use to filter specs
++       * @name Configuration#specFilter
++       * @since 3.3.0
++       * @type SpecFilter
++       * @default A function that always returns true.
++       */
++      specFilter: function() {
++        return true;
++      },
++      /**
++       * Whether or not reporters should hide disabled specs from their output.
++       * Currently only supported by Jasmine's HTMLReporter
++       * @name Configuration#hideDisabled
++       * @since 3.3.0
++       * @type Boolean
++       * @default false
++       */
++      hideDisabled: false,
++      /**
++       * Set to provide a custom promise library that Jasmine will use if it needs
++       * to create a promise. If not set, it will default to whatever global Promise
++       * library is available (if any).
++       * @name Configuration#Promise
++       * @since 3.5.0
++       * @type function
++       * @default undefined
++       */
++      Promise: undefined,
++      /**
++       * Clean closures when a suite is done running (done by clearing the stored function reference).
++       * This prevents memory leaks, but you won't be able to run jasmine multiple times.
++       * @name Configuration#autoCleanClosures
++       * @since 3.10.0
++       * @type boolean
++       * @default true
++       */
++      autoCleanClosures: true
++    };
++
++    var currentSuite = function() {
++      return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
++    };
++
++    var currentRunnable = function() {
++      return currentSpec || currentSuite();
++    };
++
++    var globalErrors = null;
++
++    var installGlobalErrors = function() {
++      if (globalErrors) {
++        return;
++      }
++
++      globalErrors = new j$.GlobalErrors();
++      globalErrors.install();
++    };
++
++    if (!options.suppressLoadErrors) {
++      installGlobalErrors();
++      globalErrors.pushListener(function(
++        message,
++        filename,
++        lineno,
++        colNo,
++        err
++      ) {
++        topSuite.result.failedExpectations.push({
++          passed: false,
++          globalErrorType: 'load',
++          message: message,
++          stack: err && err.stack,
++          filename: filename,
++          lineno: lineno
++        });
++      });
++    }
++
++    /**
++     * Configure your jasmine environment
++     * @name Env#configure
++     * @since 3.3.0
++     * @argument {Configuration} configuration
++     * @function
++     */
++    this.configure = function(configuration) {
++      var booleanProps = [
++        'random',
++        'failSpecWithNoExpectations',
++        'hideDisabled',
++        'autoCleanClosures'
++      ];
++
++      booleanProps.forEach(function(prop) {
++        if (typeof configuration[prop] !== 'undefined') {
++          config[prop] = !!configuration[prop];
++        }
++      });
++
++      if (typeof configuration.failFast !== 'undefined') {
++        if (typeof configuration.stopOnSpecFailure !== 'undefined') {
++          if (configuration.stopOnSpecFailure !== configuration.failFast) {
++            throw new Error(
++              'stopOnSpecFailure and failFast are aliases for ' +
++                "each other. Don't set failFast if you also set stopOnSpecFailure."
++            );
++          }
++        }
++
++        config.failFast = configuration.failFast;
++        config.stopOnSpecFailure = configuration.failFast;
++      } else if (typeof configuration.stopOnSpecFailure !== 'undefined') {
++        config.failFast = configuration.stopOnSpecFailure;
++        config.stopOnSpecFailure = configuration.stopOnSpecFailure;
++      }
++
++      if (typeof configuration.oneFailurePerSpec !== 'undefined') {
++        if (typeof configuration.stopSpecOnExpectationFailure !== 'undefined') {
++          if (
++            configuration.stopSpecOnExpectationFailure !==
++            configuration.oneFailurePerSpec
++          ) {
++            throw new Error(
++              'stopSpecOnExpectationFailure and oneFailurePerSpec are aliases for ' +
++                "each other. Don't set oneFailurePerSpec if you also set stopSpecOnExpectationFailure."
++            );
++          }
++        }
++
++        config.oneFailurePerSpec = configuration.oneFailurePerSpec;
++        config.stopSpecOnExpectationFailure = configuration.oneFailurePerSpec;
++      } else if (
++        typeof configuration.stopSpecOnExpectationFailure !== 'undefined'
++      ) {
++        config.oneFailurePerSpec = configuration.stopSpecOnExpectationFailure;
++        config.stopSpecOnExpectationFailure =
++          configuration.stopSpecOnExpectationFailure;
++      }
++
++      if (configuration.specFilter) {
++        config.specFilter = configuration.specFilter;
++      }
++
++      if (typeof configuration.seed !== 'undefined') {
++        config.seed = configuration.seed;
++      }
++
++      // Don't use hasOwnProperty to check for Promise existence because Promise
++      // can be initialized to undefined, either explicitly or by using the
++      // object returned from Env#configuration. In particular, Karma does this.
++      if (configuration.Promise) {
++        if (
++          typeof configuration.Promise.resolve === 'function' &&
++          typeof configuration.Promise.reject === 'function'
++        ) {
++          customPromise = configuration.Promise;
++        } else {
++          throw new Error(
++            'Custom promise library missing `resolve`/`reject` functions'
++          );
++        }
++      }
++    };
++
++    /**
++     * Get the current configuration for your jasmine environment
++     * @name Env#configuration
++     * @since 3.3.0
++     * @function
++     * @returns {Configuration}
++     */
++    this.configuration = function() {
++      var result = {};
++      for (var property in config) {
++        result[property] = config[property];
++      }
++      return result;
++    };
++
++    Object.defineProperty(this, 'specFilter', {
++      get: function() {
++        self.deprecated(
++          'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`'
++        );
++        return config.specFilter;
++      },
++      set: function(val) {
++        self.deprecated(
++          'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`'
++        );
++        config.specFilter = val;
++      }
++    });
++
++    this.setDefaultSpyStrategy = function(defaultStrategyFn) {
++      if (!currentRunnable()) {
++        throw new Error(
++          'Default spy strategy must be set in a before function or a spec'
++        );
++      }
++      runnableResources[
++        currentRunnable().id
++      ].defaultStrategyFn = defaultStrategyFn;
++    };
++
++    this.addSpyStrategy = function(name, fn) {
++      if (!currentRunnable()) {
++        throw new Error(
++          'Custom spy strategies must be added in a before function or a spec'
++        );
++      }
++      runnableResources[currentRunnable().id].customSpyStrategies[name] = fn;
++    };
++
++    this.addCustomEqualityTester = function(tester) {
++      if (!currentRunnable()) {
++        throw new Error(
++          'Custom Equalities must be added in a before function or a spec'
++        );
++      }
++      runnableResources[currentRunnable().id].customEqualityTesters.push(
++        tester
++      );
++    };
++
++    this.addMatchers = function(matchersToAdd) {
++      if (!currentRunnable()) {
++        throw new Error(
++          'Matchers must be added in a before function or a spec'
++        );
++      }
++      var customMatchers =
++        runnableResources[currentRunnable().id].customMatchers;
++
++      for (var matcherName in matchersToAdd) {
++        customMatchers[matcherName] = matchersToAdd[matcherName];
++      }
++    };
++
++    this.addAsyncMatchers = function(matchersToAdd) {
++      if (!currentRunnable()) {
++        throw new Error(
++          'Async Matchers must be added in a before function or a spec'
++        );
++      }
++      var customAsyncMatchers =
++        runnableResources[currentRunnable().id].customAsyncMatchers;
++
++      for (var matcherName in matchersToAdd) {
++        customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
++      }
++    };
++
++    this.addCustomObjectFormatter = function(formatter) {
++      if (!currentRunnable()) {
++        throw new Error(
++          'Custom object formatters must be added in a before function or a spec'
++        );
++      }
++
++      runnableResources[currentRunnable().id].customObjectFormatters.push(
++        formatter
++      );
++    };
++
++    j$.Expectation.addCoreMatchers(j$.matchers);
++    j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
++
++    var nextSpecId = 0;
++    var getNextSpecId = function() {
++      return 'spec' + nextSpecId++;
++    };
++
++    var nextSuiteId = 0;
++    var getNextSuiteId = function() {
++      return 'suite' + nextSuiteId++;
++    };
++
++    var makePrettyPrinter = function() {
++      var customObjectFormatters =
++        runnableResources[currentRunnable().id].customObjectFormatters;
++      return j$.makePrettyPrinter(customObjectFormatters);
++    };
++
++    var makeMatchersUtil = function() {
++      var customEqualityTesters =
++        runnableResources[currentRunnable().id].customEqualityTesters;
++      return new j$.MatchersUtil({
++        customTesters: customEqualityTesters,
++        pp: makePrettyPrinter()
++      });
++    };
++
++    var expectationFactory = function(actual, spec) {
++      var customEqualityTesters =
++        runnableResources[spec.id].customEqualityTesters;
++
++      return j$.Expectation.factory({
++        matchersUtil: makeMatchersUtil(),
++        customEqualityTesters: customEqualityTesters,
++        customMatchers: runnableResources[spec.id].customMatchers,
++        actual: actual,
++        addExpectationResult: addExpectationResult
++      });
++
++      function addExpectationResult(passed, result) {
++        return spec.addExpectationResult(passed, result);
++      }
++    };
++
++    function recordLateExpectation(runable, runableType, result) {
++      var delayedExpectationResult = {};
++      Object.keys(result).forEach(function(k) {
++        delayedExpectationResult[k] = result[k];
++      });
++      delayedExpectationResult.passed = false;
++      delayedExpectationResult.globalErrorType = 'lateExpectation';
++      delayedExpectationResult.message =
++        runableType +
++        ' "' +
++        runable.getFullName() +
++        '" ran a "' +
++        result.matcherName +
++        '" expectation after it finished.\n';
++
++      if (result.message) {
++        delayedExpectationResult.message +=
++          'Message: "' + result.message + '"\n';
++      }
++
++      delayedExpectationResult.message +=
++        '1. Did you forget to return or await the result of expectAsync?\n' +
++        '2. Was done() invoked before an async operation completed?\n' +
++        '3. Did an expectation follow a call to done()?';
++
++      topSuite.result.failedExpectations.push(delayedExpectationResult);
++    }
++
++    var asyncExpectationFactory = function(actual, spec, runableType) {
++      return j$.Expectation.asyncFactory({
++        matchersUtil: makeMatchersUtil(),
++        customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
++        customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers,
++        actual: actual,
++        addExpectationResult: addExpectationResult
++      });
++
++      function addExpectationResult(passed, result) {
++        if (currentRunnable() !== spec) {
++          recordLateExpectation(spec, runableType, result);
++        }
++        return spec.addExpectationResult(passed, result);
++      }
++    };
++    var suiteAsyncExpectationFactory = function(actual, suite) {
++      return asyncExpectationFactory(actual, suite, 'Suite');
++    };
++
++    var specAsyncExpectationFactory = function(actual, suite) {
++      return asyncExpectationFactory(actual, suite, 'Spec');
++    };
++
++    var defaultResourcesForRunnable = function(id, parentRunnableId) {
++      var resources = {
++        spies: [],
++        customEqualityTesters: [],
++        customMatchers: {},
++        customAsyncMatchers: {},
++        customSpyStrategies: {},
++        defaultStrategyFn: undefined,
++        customObjectFormatters: []
++      };
++
++      if (runnableResources[parentRunnableId]) {
++        resources.customEqualityTesters = j$.util.clone(
++          runnableResources[parentRunnableId].customEqualityTesters
++        );
++        resources.customMatchers = j$.util.clone(
++          runnableResources[parentRunnableId].customMatchers
++        );
++        resources.customAsyncMatchers = j$.util.clone(
++          runnableResources[parentRunnableId].customAsyncMatchers
++        );
++        resources.customObjectFormatters = j$.util.clone(
++          runnableResources[parentRunnableId].customObjectFormatters
++        );
++        resources.defaultStrategyFn =
++          runnableResources[parentRunnableId].defaultStrategyFn;
++      }
++
++      runnableResources[id] = resources;
++    };
++
++    var clearResourcesForRunnable = function(id) {
++      spyRegistry.clearSpies();
++      delete runnableResources[id];
++    };
++
++    var beforeAndAfterFns = function(targetSuite) {
++      return function() {
++        var befores = [],
++          afters = [],
++          suite = targetSuite;
++
++        while (suite) {
++          befores = befores.concat(suite.beforeFns);
++          afters = afters.concat(suite.afterFns);
++
++          suite = suite.parentSuite;
++        }
++
++        return {
++          befores: befores.reverse(),
++          afters: afters
++        };
++      };
++    };
++
++    var getSpecName = function(spec, suite) {
++      var fullName = [spec.description],
++        suiteFullName = suite.getFullName();
++
++      if (suiteFullName !== '') {
++        fullName.unshift(suiteFullName);
++      }
++      return fullName.join(' ');
++    };
++
++    // TODO: we may just be able to pass in the fn instead of wrapping here
++    var buildExpectationResult = j$.buildExpectationResult,
++      exceptionFormatter = new j$.ExceptionFormatter(),
++      expectationResultFactory = function(attrs) {
++        attrs.messageFormatter = exceptionFormatter.message;
++        attrs.stackFormatter = exceptionFormatter.stack;
++
++        return buildExpectationResult(attrs);
++      };
++
++    /**
++     * Sets whether Jasmine should throw an Error when an expectation fails.
++     * This causes a spec to only have one expectation failure.
++     * @name Env#throwOnExpectationFailure
++     * @since 2.3.0
++     * @function
++     * @param {Boolean} value Whether to throw when a expectation fails
++     * @deprecated Use the `stopSpecOnExpectationFailure` option with {@link Env#configure}
++     */
++    this.throwOnExpectationFailure = function(value) {
++      this.deprecated(
++        'Setting throwOnExpectationFailure directly on Env is deprecated and ' +
++          'will be removed in a future version of Jasmine. Please use the ' +
++          'stopSpecOnExpectationFailure option in `configure`.'
++      );
++      this.configure({ oneFailurePerSpec: !!value });
++    };
++
++    this.throwingExpectationFailures = function() {
++      this.deprecated(
++        'Getting throwingExpectationFailures directly from Env is deprecated ' +
++          'and will be removed in a future version of Jasmine. Please check ' +
++          'the stopSpecOnExpectationFailure option from `configuration`.'
++      );
++      return config.oneFailurePerSpec;
++    };
++
++    /**
++     * Set whether to stop suite execution when a spec fails
++     * @name Env#stopOnSpecFailure
++     * @since 2.7.0
++     * @function
++     * @param {Boolean} value Whether to stop suite execution when a spec fails
++     * @deprecated Use the `stopOnSpecFailure` option with {@link Env#configure}
++     */
++    this.stopOnSpecFailure = function(value) {
++      this.deprecated(
++        'Setting stopOnSpecFailure directly is deprecated and will be ' +
++          'removed in a future version of Jasmine. Please use the ' +
++          'stopOnSpecFailure option in `configure`.'
++      );
++      this.configure({ stopOnSpecFailure: !!value });
++    };
++
++    this.stoppingOnSpecFailure = function() {
++      this.deprecated(
++        'Getting stoppingOnSpecFailure directly from Env is deprecated and ' +
++          'will be removed in a future version of Jasmine. Please check the ' +
++          'stopOnSpecFailure option from `configuration`.'
++      );
++      return config.failFast;
++    };
++
++    /**
++     * Set whether to randomize test execution order
++     * @name Env#randomizeTests
++     * @since 2.4.0
++     * @function
++     * @param {Boolean} value Whether to randomize execution order
++     * @deprecated Use the `random` option with {@link Env#configure}
++     */
++    this.randomizeTests = function(value) {
++      this.deprecated(
++        'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`'
++      );
++      config.random = !!value;
++    };
++
++    this.randomTests = function() {
++      this.deprecated(
++        'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`'
++      );
++      return config.random;
++    };
++
++    /**
++     * Set the random number seed for spec randomization
++     * @name Env#seed
++     * @since 2.4.0
++     * @function
++     * @param {Number} value The seed value
++     * @deprecated Use the `seed` option with {@link Env#configure}
++     */
++    this.seed = function(value) {
++      this.deprecated(
++        'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`'
++      );
++      if (value) {
++        config.seed = value;
++      }
++      return config.seed;
++    };
++
++    this.hidingDisabled = function(value) {
++      this.deprecated(
++        'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`'
++      );
++      return config.hideDisabled;
++    };
++
++    /**
++     * @name Env#hideDisabled
++     * @since 3.2.0
++     * @function
++     * @deprecated Use the `hideDisabled` option with {@link Env#configure}
++     */
++    this.hideDisabled = function(value) {
++      this.deprecated(
++        'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`'
++      );
++      config.hideDisabled = !!value;
++    };
++
++    this.deprecated = function(deprecation) {
++      var runnable = currentRunnable() || topSuite;
++      var context;
++
++      if (runnable === topSuite) {
++        context = '';
++      } else if (runnable === currentSuite()) {
++        context = ' (in suite: ' + runnable.getFullName() + ')';
++      } else {
++        context = ' (in spec: ' + runnable.getFullName() + ')';
++      }
++
++      runnable.addDeprecationWarning(deprecation);
++      if (
++        typeof console !== 'undefined' &&
++        typeof console.error === 'function'
++      ) {
++        console.error('DEPRECATION: ' + deprecation + context);
++      }
++    };
++
++    var queueRunnerFactory = function(options, args) {
++      var failFast = false;
++      if (options.isLeaf) {
++        failFast = config.stopSpecOnExpectationFailure;
++      } else if (!options.isReporter) {
++        failFast = config.stopOnSpecFailure;
++      }
++      options.clearStack = options.clearStack || clearStack;
++      options.timeout = {
++        setTimeout: realSetTimeout,
++        clearTimeout: realClearTimeout
++      };
++      options.fail = self.fail;
++      options.globalErrors = globalErrors;
++      options.completeOnFirstError = failFast;
++      options.onException =
++        options.onException ||
++        function(e) {
++          (currentRunnable() || topSuite).onException(e);
++        };
++      options.deprecated = self.deprecated;
++
++      new j$.QueueRunner(options).execute(args);
++    };
++
++    var topSuite = new j$.Suite({
++      env: this,
++      id: getNextSuiteId(),
++      description: 'Jasmine__TopLevel__Suite',
++      expectationFactory: expectationFactory,
++      asyncExpectationFactory: suiteAsyncExpectationFactory,
++      expectationResultFactory: expectationResultFactory,
++      autoCleanClosures: config.autoCleanClosures
++    });
++    currentDeclarationSuite = topSuite;
++
++    /**
++     * Provides the root suite, through which all suites and specs can be
++     * accessed.
++     * @function
++     * @name Env#topSuite
++     * @return {Suite} the root suite
++     * @since 2.0.0
++     */
++    this.topSuite = function() {
++      return topSuite;
++    };
++
++    /**
++     * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
++     * @interface Reporter
++     * @see custom_reporter
++     */
++    var reporter = new j$.ReportDispatcher(
++      [
++        /**
++         * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
++         * @function
++         * @name Reporter#jasmineStarted
++         * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
++         * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++         * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++         * @see async
++         */
++        'jasmineStarted',
++        /**
++         * When the entire suite has finished execution `jasmineDone` is called
++         * @function
++         * @name Reporter#jasmineDone
++         * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
++         * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++         * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++         * @see async
++         */
++        'jasmineDone',
++        /**
++         * `suiteStarted` is invoked when a `describe` starts to run
++         * @function
++         * @name Reporter#suiteStarted
++         * @param {SuiteResult} result Information about the individual {@link describe} being run
++         * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++         * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++         * @see async
++         */
++        'suiteStarted',
++        /**
++         * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
++         *
++         * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
++         * @function
++         * @name Reporter#suiteDone
++         * @param {SuiteResult} result
++         * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++         * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++         * @see async
++         */
++        'suiteDone',
++        /**
++         * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
++         * @function
++         * @name Reporter#specStarted
++         * @param {SpecResult} result Information about the individual {@link it} being run
++         * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++         * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++         * @see async
++         */
++        'specStarted',
++        /**
++         * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
++         *
++         * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
++         * @function
++         * @name Reporter#specDone
++         * @param {SpecResult} result
++         * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++         * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++         * @see async
++         */
++        'specDone'
++      ],
++      queueRunnerFactory
++    );
++
++    /**
++     * Executes the specs.
++     *
++     * If called with no parameters or with a falsy value as the first parameter,
++     * all specs will be executed except those that are excluded by a
++     * [spec filter]{@link Configuration#specFilter} or other mechanism. If the
++     * first parameter is a list of spec/suite IDs, only those specs/suites will
++     * be run.
++     *
++     * Both parameters are optional, but a completion callback is only valid as
++     * the second parameter. To specify a completion callback but not a list of
++     * specs/suites to run, pass null or undefined as the first parameter.
++     *
++     * execute should not be called more than once.
++     *
++     * If the environment supports promises, execute will return a promise that
++     * is resolved after the suite finishes executing. The promise will be
++     * resolved (not rejected) as long as the suite runs to completion. Use a
++     * {@link Reporter} to determine whether or not the suite passed.
++     *
++     * @name Env#execute
++     * @since 2.0.0
++     * @function
++     * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
++     * @param {Function=} onComplete Function that will be called after all specs have run
++     * @return {Promise<undefined>}
++     */
++    this.execute = function(runnablesToRun, onComplete) {
++      if (this._executedBefore) {
++        topSuite.reset();
++      }
++      this._executedBefore = true;
++      defaultResourcesForRunnable(topSuite.id);
++      installGlobalErrors();
++
++      if (!runnablesToRun) {
++        if (focusedRunnables.length) {
++          runnablesToRun = focusedRunnables;
++        } else {
++          runnablesToRun = [topSuite.id];
++        }
++      }
++
++      var order = new j$.Order({
++        random: config.random,
++        seed: config.seed
++      });
++
++      var processor = new j$.TreeProcessor({
++        tree: topSuite,
++        runnableIds: runnablesToRun,
++        queueRunnerFactory: queueRunnerFactory,
++        failSpecWithNoExpectations: config.failSpecWithNoExpectations,
++        nodeStart: function(suite, next) {
++          currentlyExecutingSuites.push(suite);
++          defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
++          reporter.suiteStarted(suite.result, next);
++          suite.startTimer();
++        },
++        nodeComplete: function(suite, result, next) {
++          if (suite !== currentSuite()) {
++            throw new Error('Tried to complete the wrong suite');
++          }
++
++          clearResourcesForRunnable(suite.id);
++          currentlyExecutingSuites.pop();
++
++          if (result.status === 'failed') {
++            hasFailures = true;
++          }
++          suite.endTimer();
++          reporter.suiteDone(result, next);
++        },
++        orderChildren: function(node) {
++          return order.sort(node.children);
++        },
++        excludeNode: function(spec) {
++          return !config.specFilter(spec);
++        }
++      });
++
++      if (!processor.processTree().valid) {
++        throw new Error(
++          'Invalid order: would cause a beforeAll or afterAll to be run multiple times'
++        );
++      }
++
++      var jasmineTimer = new j$.Timer();
++      jasmineTimer.start();
++
++      var Promise = customPromise || global.Promise;
++
++      if (Promise) {
++        return new Promise(function(resolve) {
++          runAll(function() {
++            if (onComplete) {
++              onComplete();
++            }
++
++            resolve();
++          });
++        });
++      } else {
++        runAll(function() {
++          if (onComplete) {
++            onComplete();
++          }
++        });
++      }
++
++      function runAll(done) {
++        /**
++         * Information passed to the {@link Reporter#jasmineStarted} event.
++         * @typedef JasmineStartedInfo
++         * @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
++         * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
++         * @since 2.0.0
++         */
++        reporter.jasmineStarted(
++          {
++            totalSpecsDefined: totalSpecsDefined,
++            order: order
++          },
++          function() {
++            currentlyExecutingSuites.push(topSuite);
++
++            processor.execute(function() {
++              clearResourcesForRunnable(topSuite.id);
++              currentlyExecutingSuites.pop();
++              var overallStatus, incompleteReason;
++
++              if (
++                hasFailures ||
++                topSuite.result.failedExpectations.length > 0
++              ) {
++                overallStatus = 'failed';
++              } else if (focusedRunnables.length > 0) {
++                overallStatus = 'incomplete';
++                incompleteReason = 'fit() or fdescribe() was found';
++              } else if (totalSpecsDefined === 0) {
++                overallStatus = 'incomplete';
++                incompleteReason = 'No specs found';
++              } else {
++                overallStatus = 'passed';
++              }
++
++              /**
++               * Information passed to the {@link Reporter#jasmineDone} event.
++               * @typedef JasmineDoneInfo
++               * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
++               * @property {Int} totalTime - The total time (in ms) that it took to execute the suite
++               * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
++               * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
++               * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
++               * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
++               * @since 2.4.0
++               */
++              reporter.jasmineDone(
++                {
++                  overallStatus: overallStatus,
++                  totalTime: jasmineTimer.elapsed(),
++                  incompleteReason: incompleteReason,
++                  order: order,
++                  failedExpectations: topSuite.result.failedExpectations,
++                  deprecationWarnings: topSuite.result.deprecationWarnings
++                },
++                done
++              );
++            });
++          }
++        );
++      }
++    };
++
++    /**
++     * Add a custom reporter to the Jasmine environment.
++     * @name Env#addReporter
++     * @since 2.0.0
++     * @function
++     * @param {Reporter} reporterToAdd The reporter to be added.
++     * @see custom_reporter
++     */
++    this.addReporter = function(reporterToAdd) {
++      reporter.addReporter(reporterToAdd);
++    };
++
++    /**
++     * Provide a fallback reporter if no other reporters have been specified.
++     * @name Env#provideFallbackReporter
++     * @since 2.5.0
++     * @function
++     * @param {Reporter} reporterToAdd The reporter
++     * @see custom_reporter
++     */
++    this.provideFallbackReporter = function(reporterToAdd) {
++      reporter.provideFallbackReporter(reporterToAdd);
++    };
++
++    /**
++     * Clear all registered reporters
++     * @name Env#clearReporters
++     * @since 2.5.2
++     * @function
++     */
++    this.clearReporters = function() {
++      reporter.clearReporters();
++    };
++
++    var spyFactory = new j$.SpyFactory(
++      function getCustomStrategies() {
++        var runnable = currentRunnable();
++
++        if (runnable) {
++          return runnableResources[runnable.id].customSpyStrategies;
++        }
++
++        return {};
++      },
++      function getDefaultStrategyFn() {
++        var runnable = currentRunnable();
++
++        if (runnable) {
++          return runnableResources[runnable.id].defaultStrategyFn;
++        }
++
++        return undefined;
++      },
++      function getPromise() {
++        return customPromise || global.Promise;
++      }
++    );
++
++    var spyRegistry = new j$.SpyRegistry({
++      currentSpies: function() {
++        if (!currentRunnable()) {
++          throw new Error(
++            'Spies must be created in a before function or a spec'
++          );
++        }
++        return runnableResources[currentRunnable().id].spies;
++      },
++      createSpy: function(name, originalFn) {
++        return self.createSpy(name, originalFn);
++      }
++    });
++
++    /**
++     * Configures whether Jasmine should allow the same function to be spied on
++     * more than once during the execution of a spec. By default, spying on
++     * a function that is already a spy will cause an error.
++     * @name Env#allowRespy
++     * @function
++     * @since 2.5.0
++     * @param {boolean} allow Whether to allow respying
++     */
++    this.allowRespy = function(allow) {
++      spyRegistry.allowRespy(allow);
++    };
++
++    this.spyOn = function() {
++      return spyRegistry.spyOn.apply(spyRegistry, arguments);
++    };
++
++    this.spyOnProperty = function() {
++      return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
++    };
++
++    this.spyOnAllFunctions = function() {
++      return spyRegistry.spyOnAllFunctions.apply(spyRegistry, arguments);
++    };
++
++    this.createSpy = function(name, originalFn) {
++      if (arguments.length === 1 && j$.isFunction_(name)) {
++        originalFn = name;
++        name = originalFn.name;
++      }
++
++      return spyFactory.createSpy(name, originalFn);
++    };
++
++    this.createSpyObj = function(baseName, methodNames, propertyNames) {
++      return spyFactory.createSpyObj(baseName, methodNames, propertyNames);
++    };
++
++    var ensureIsFunction = function(fn, caller) {
++      if (!j$.isFunction_(fn)) {
++        throw new Error(
++          caller + ' expects a function argument; received ' + j$.getType_(fn)
++        );
++      }
++    };
++
++    var ensureIsFunctionOrAsync = function(fn, caller) {
++      if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
++        throw new Error(
++          caller + ' expects a function argument; received ' + j$.getType_(fn)
++        );
++      }
++    };
++
++    function ensureIsNotNested(method) {
++      var runnable = currentRunnable();
++      if (runnable !== null && runnable !== undefined) {
++        throw new Error(
++          "'" + method + "' should only be used in 'describe' function"
++        );
++      }
++    }
++
++    var suiteFactory = function(description) {
++      var suite = new j$.Suite({
++        env: self,
++        id: getNextSuiteId(),
++        description: description,
++        parentSuite: currentDeclarationSuite,
++        timer: new j$.Timer(),
++        expectationFactory: expectationFactory,
++        asyncExpectationFactory: suiteAsyncExpectationFactory,
++        expectationResultFactory: expectationResultFactory,
++        throwOnExpectationFailure: config.oneFailurePerSpec,
++        autoCleanClosures: config.autoCleanClosures
++      });
++
++      return suite;
++    };
++
++    this.describe = function(description, specDefinitions) {
++      //ensureIsNotNested('describe');
++      ensureIsFunction(specDefinitions, 'describe');
++      var suite = suiteFactory(description);
++      if (specDefinitions.length > 0) {
++        throw new Error('describe does not expect any arguments');
++      }
++      if (currentDeclarationSuite.markedExcluding) {
++        suite.exclude();
++      }
++      addSpecsToSuite(suite, specDefinitions);
++      return suite;
++    };
++
++    this.xdescribe = function(description, specDefinitions) {
++      ensureIsNotNested('xdescribe');
++      ensureIsFunction(specDefinitions, 'xdescribe');
++      var suite = suiteFactory(description);
++      suite.exclude();
++      addSpecsToSuite(suite, specDefinitions);
++      return suite;
++    };
++
++    var focusedRunnables = [];
++
++    this.fdescribe = function(description, specDefinitions) {
++      ensureIsNotNested('fdescribe');
++      ensureIsFunction(specDefinitions, 'fdescribe');
++      var suite = suiteFactory(description);
++      suite.isFocused = true;
++
++      focusedRunnables.push(suite.id);
++      unfocusAncestor();
++      addSpecsToSuite(suite, specDefinitions);
++
++      return suite;
++    };
++
++    function addSpecsToSuite(suite, specDefinitions) {
++      var parentSuite = currentDeclarationSuite;
++      parentSuite.addChild(suite);
++      currentDeclarationSuite = suite;
++
++      var declarationError = null;
++      try {
++        specDefinitions.call(suite);
++      } catch (e) {
++        declarationError = e;
++      }
++
++      if (declarationError) {
++        suite.onException(declarationError);
++      }
++
++      currentDeclarationSuite = parentSuite;
++    }
++
++    function findFocusedAncestor(suite) {
++      while (suite) {
++        if (suite.isFocused) {
++          return suite.id;
++        }
++        suite = suite.parentSuite;
++      }
++
++      return null;
++    }
++
++    function unfocusAncestor() {
++      var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
++      if (focusedAncestor) {
++        for (var i = 0; i < focusedRunnables.length; i++) {
++          if (focusedRunnables[i] === focusedAncestor) {
++            focusedRunnables.splice(i, 1);
++            break;
++          }
++        }
++      }
++    }
++
++    var specFactory = function(description, fn, suite, timeout) {
++      totalSpecsDefined++;
++      var spec = new j$.Spec({
++        id: getNextSpecId(),
++        beforeAndAfterFns: beforeAndAfterFns(suite),
++        expectationFactory: expectationFactory,
++        asyncExpectationFactory: specAsyncExpectationFactory,
++        resultCallback: specResultCallback,
++        getSpecName: function(spec) {
++          return getSpecName(spec, suite);
++        },
++        onStart: specStarted,
++        description: description,
++        expectationResultFactory: expectationResultFactory,
++        queueRunnerFactory: queueRunnerFactory,
++        userContext: function() {
++          return suite.clonedSharedUserContext();
++        },
++        queueableFn: {
++          fn: fn,
++          timeout: timeout || 0
++        },
++        throwOnExpectationFailure: config.oneFailurePerSpec,
++        autoCleanClosures: config.autoCleanClosures,
++        timer: new j$.Timer()
++      });
++      return spec;
++
++      function specResultCallback(result, next) {
++        clearResourcesForRunnable(spec.id);
++        currentSpec = null;
++
++        if (result.status === 'failed') {
++          hasFailures = true;
++        }
++
++        reporter.specDone(result, next);
++      }
++
++      function specStarted(spec, next) {
++        currentSpec = spec;
++        defaultResourcesForRunnable(spec.id, suite.id);
++        reporter.specStarted(spec.result, next);
++      }
++    };
++
++    this.it = function(description, fn, timeout) {
++      ensureIsNotNested('it');
++      // it() sometimes doesn't have a fn argument, so only check the type if
++      // it's given.
++      if (arguments.length > 1 && typeof fn !== 'undefined') {
++        ensureIsFunctionOrAsync(fn, 'it');
++      }
++
++      if (timeout) {
++        j$.util.validateTimeout(timeout);
++      }
++
++      var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
++      if (currentDeclarationSuite.markedExcluding) {
++        spec.exclude();
++      }
++      currentDeclarationSuite.addChild(spec);
++      return spec;
++    };
++
++    this.xit = function(description, fn, timeout) {
++      ensureIsNotNested('xit');
++      // xit(), like it(), doesn't always have a fn argument, so only check the
++      // type when needed.
++      if (arguments.length > 1 && typeof fn !== 'undefined') {
++        ensureIsFunctionOrAsync(fn, 'xit');
++      }
++      var spec = this.it.apply(this, arguments);
++      spec.exclude('Temporarily disabled with xit');
++      return spec;
++    };
++
++    this.fit = function(description, fn, timeout) {
++      ensureIsNotNested('fit');
++      ensureIsFunctionOrAsync(fn, 'fit');
++
++      if (timeout) {
++        j$.util.validateTimeout(timeout);
++      }
++      var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
++      currentDeclarationSuite.addChild(spec);
++      focusedRunnables.push(spec.id);
++      unfocusAncestor();
++      return spec;
++    };
++
++    /**
++     * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult}
++     * @name Env#setSpecProperty
++     * @since 3.6.0
++     * @function
++     * @param {String} key The name of the property
++     * @param {*} value The value of the property
++     */
++    this.setSpecProperty = function(key, value) {
++      if (!currentRunnable() || currentRunnable() == currentSuite()) {
++        throw new Error(
++          "'setSpecProperty' was used when there was no current spec"
++        );
++      }
++      currentRunnable().setSpecProperty(key, value);
++    };
++
++    /**
++     * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult}
++     * @name Env#setSuiteProperty
++     * @since 3.6.0
++     * @function
++     * @param {String} key The name of the property
++     * @param {*} value The value of the property
++     */
++    this.setSuiteProperty = function(key, value) {
++      if (!currentSuite()) {
++        throw new Error(
++          "'setSuiteProperty' was used when there was no current suite"
++        );
++      }
++      currentSuite().setSuiteProperty(key, value);
++    };
++
++    this.expect = function(actual) {
++      if (!currentRunnable()) {
++        throw new Error(
++          "'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
++        );
++      }
++
++      return currentRunnable().expect(actual);
++    };
++
++    this.expectAsync = function(actual) {
++      if (!currentRunnable()) {
++        throw new Error(
++          "'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
++        );
++      }
++
++      return currentRunnable().expectAsync(actual);
++    };
++
++    this.beforeEach = function(beforeEachFunction, timeout) {
++      ensureIsNotNested('beforeEach');
++      ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
++
++      if (timeout) {
++        j$.util.validateTimeout(timeout);
++      }
++
++      currentDeclarationSuite.beforeEach({
++        fn: beforeEachFunction,
++        timeout: timeout || 0
++      });
++    };
++
++    this.beforeAll = function(beforeAllFunction, timeout) {
++      ensureIsNotNested('beforeAll');
++      ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
++
++      if (timeout) {
++        j$.util.validateTimeout(timeout);
++      }
++
++      currentDeclarationSuite.beforeAll({
++        fn: beforeAllFunction,
++        timeout: timeout || 0
++      });
++    };
++
++    this.afterEach = function(afterEachFunction, timeout) {
++      ensureIsNotNested('afterEach');
++      ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
++
++      if (timeout) {
++        j$.util.validateTimeout(timeout);
++      }
++
++      afterEachFunction.isCleanup = true;
++      currentDeclarationSuite.afterEach({
++        fn: afterEachFunction,
++        timeout: timeout || 0
++      });
++    };
++
++    this.afterAll = function(afterAllFunction, timeout) {
++      ensureIsNotNested('afterAll');
++      ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
++
++      if (timeout) {
++        j$.util.validateTimeout(timeout);
++      }
++
++      currentDeclarationSuite.afterAll({
++        fn: afterAllFunction,
++        timeout: timeout || 0
++      });
++    };
++
++    this.pending = function(message) {
++      var fullMessage = j$.Spec.pendingSpecExceptionMessage;
++      if (message) {
++        fullMessage += message;
++      }
++      throw fullMessage;
++    };
++
++    this.fail = function(error) {
++      if (!currentRunnable()) {
++        throw new Error(
++          "'fail' was used when there was no current spec, this could be because an asynchronous test timed out"
++        );
++      }
++
++      var message = 'Failed';
++      if (error) {
++        message += ': ';
++        if (error.message) {
++          message += error.message;
++        } else if (j$.isString_(error)) {
++          message += error;
++        } else {
++          // pretty print all kind of objects. This includes arrays.
++          message += makePrettyPrinter()(error);
++        }
++      }
++
++      currentRunnable().addExpectationResult(false, {
++        matcherName: '',
++        passed: false,
++        expected: '',
++        actual: '',
++        message: message,
++        error: error && error.message ? error : null
++      });
++
++      if (config.oneFailurePerSpec) {
++        throw new Error(message);
++      }
++    };
++
++    this.cleanup_ = function() {
++      if (globalErrors) {
++        globalErrors.uninstall();
++      }
++    };
++  }
++
++  return Env;
++};
++
++getJasmineRequireObj().JsApiReporter = function(j$) {
++  /**
++   * @name jsApiReporter
++   * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object.
++   * @class
++   * @hideconstructor
++   */
++  function JsApiReporter(options) {
++    var timer = options.timer || new j$.Timer(),
++      status = 'loaded';
++
++    this.started = false;
++    this.finished = false;
++    this.runDetails = {};
++
++    this.jasmineStarted = function() {
++      this.started = true;
++      status = 'started';
++      timer.start();
++    };
++
++    var executionTime;
++
++    this.jasmineDone = function(runDetails) {
++      this.finished = true;
++      this.runDetails = runDetails;
++      executionTime = timer.elapsed();
++      status = 'done';
++    };
++
++    /**
++     * Get the current status for the Jasmine environment.
++     * @name jsApiReporter#status
++     * @since 2.0.0
++     * @function
++     * @return {String} - One of `loaded`, `started`, or `done`
++     */
++    this.status = function() {
++      return status;
++    };
++
++    var suites = [],
++      suites_hash = {};
++
++    this.suiteStarted = function(result) {
++      suites_hash[result.id] = result;
++    };
++
++    this.suiteDone = function(result) {
++      storeSuite(result);
++    };
++
++    /**
++     * Get the results for a set of suites.
++     *
++     * Retrievable in slices for easier serialization.
++     * @name jsApiReporter#suiteResults
++     * @since 2.1.0
++     * @function
++     * @param {Number} index - The position in the suites list to start from.
++     * @param {Number} length - Maximum number of suite results to return.
++     * @return {SuiteResult[]}
++     */
++    this.suiteResults = function(index, length) {
++      return suites.slice(index, index + length);
++    };
++
++    function storeSuite(result) {
++      suites.push(result);
++      suites_hash[result.id] = result;
++    }
++
++    /**
++     * Get all of the suites in a single object, with their `id` as the key.
++     * @name jsApiReporter#suites
++     * @since 2.0.0
++     * @function
++     * @return {Object} - Map of suite id to {@link SuiteResult}
++     */
++    this.suites = function() {
++      return suites_hash;
++    };
++
++    var specs = [];
++
++    this.specDone = function(result) {
++      specs.push(result);
++    };
++
++    /**
++     * Get the results for a set of specs.
++     *
++     * Retrievable in slices for easier serialization.
++     * @name jsApiReporter#specResults
++     * @since 2.0.0
++     * @function
++     * @param {Number} index - The position in the specs list to start from.
++     * @param {Number} length - Maximum number of specs results to return.
++     * @return {SpecResult[]}
++     */
++    this.specResults = function(index, length) {
++      return specs.slice(index, index + length);
++    };
++
++    /**
++     * Get all spec results.
++     * @name jsApiReporter#specs
++     * @since 2.0.0
++     * @function
++     * @return {SpecResult[]}
++     */
++    this.specs = function() {
++      return specs;
++    };
++
++    /**
++     * Get the number of milliseconds it took for the full Jasmine suite to run.
++     * @name jsApiReporter#executionTime
++     * @since 2.0.0
++     * @function
++     * @return {Number}
++     */
++    this.executionTime = function() {
++      return executionTime;
++    };
++  }
++
++  return JsApiReporter;
++};
++
++getJasmineRequireObj().Any = function(j$) {
++  function Any(expectedObject) {
++    if (typeof expectedObject === 'undefined') {
++      throw new TypeError(
++        'jasmine.any() expects to be passed a constructor function. ' +
++          'Please pass one or use jasmine.anything() to match any object.'
++      );
++    }
++    this.expectedObject = expectedObject;
++  }
++
++  Any.prototype.asymmetricMatch = function(other) {
++    if (this.expectedObject == String) {
++      return typeof other == 'string' || other instanceof String;
++    }
++
++    if (this.expectedObject == Number) {
++      return typeof other == 'number' || other instanceof Number;
++    }
++
++    if (this.expectedObject == Function) {
++      return typeof other == 'function' || other instanceof Function;
++    }
++
++    if (this.expectedObject == Object) {
++      return other !== null && typeof other == 'object';
++    }
++
++    if (this.expectedObject == Boolean) {
++      return typeof other == 'boolean';
++    }
++
++    /* jshint -W122 */
++    /* global Symbol */
++    if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
++      return typeof other == 'symbol';
++    }
++    /* jshint +W122 */
++
++    return other instanceof this.expectedObject;
++  };
++
++  Any.prototype.jasmineToString = function() {
++    return '<jasmine.any(' + j$.fnNameFor(this.expectedObject) + ')>';
++  };
++
++  return Any;
++};
++
++getJasmineRequireObj().Anything = function(j$) {
++  function Anything() {}
++
++  Anything.prototype.asymmetricMatch = function(other) {
++    return !j$.util.isUndefined(other) && other !== null;
++  };
++
++  Anything.prototype.jasmineToString = function() {
++    return '<jasmine.anything>';
++  };
++
++  return Anything;
++};
++
++getJasmineRequireObj().ArrayContaining = function(j$) {
++  function ArrayContaining(sample) {
++    this.sample = sample;
++  }
++
++  ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
++    if (!j$.isArray_(this.sample)) {
++      throw new Error(
++        'You must provide an array to arrayContaining, not ' +
++          j$.pp(this.sample) +
++          '.'
++      );
++    }
++
++    // If the actual parameter is not an array, we can fail immediately, since it couldn't
++    // possibly be an "array containing" anything. However, we also want an empty sample
++    // array to match anything, so we need to double-check we aren't in that case
++    if (!j$.isArray_(other) && this.sample.length > 0) {
++      return false;
++    }
++
++    for (var i = 0; i < this.sample.length; i++) {
++      var item = this.sample[i];
++      if (!matchersUtil.contains(other, item)) {
++        return false;
++      }
++    }
++
++    return true;
++  };
++
++  ArrayContaining.prototype.jasmineToString = function(pp) {
++    return '<jasmine.arrayContaining(' + pp(this.sample) + ')>';
++  };
++
++  return ArrayContaining;
++};
++
++getJasmineRequireObj().ArrayWithExactContents = function(j$) {
++  function ArrayWithExactContents(sample) {
++    this.sample = sample;
++  }
++
++  ArrayWithExactContents.prototype.asymmetricMatch = function(
++    other,
++    matchersUtil
++  ) {
++    if (!j$.isArray_(this.sample)) {
++      throw new Error(
++        'You must provide an array to arrayWithExactContents, not ' +
++          j$.pp(this.sample) +
++          '.'
++      );
++    }
++
++    if (this.sample.length !== other.length) {
++      return false;
++    }
++
++    for (var i = 0; i < this.sample.length; i++) {
++      var item = this.sample[i];
++      if (!matchersUtil.contains(other, item)) {
++        return false;
++      }
++    }
++
++    return true;
++  };
++
++  ArrayWithExactContents.prototype.jasmineToString = function(pp) {
++    return '<jasmine.arrayWithExactContents(' + pp(this.sample) + ')>';
++  };
++
++  return ArrayWithExactContents;
++};
++
++getJasmineRequireObj().Empty = function(j$) {
++  function Empty() {}
++
++  Empty.prototype.asymmetricMatch = function(other) {
++    if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
++      return other.length === 0;
++    }
++
++    if (j$.isMap(other) || j$.isSet(other)) {
++      return other.size === 0;
++    }
++
++    if (j$.isObject_(other)) {
++      return Object.keys(other).length === 0;
++    }
++    return false;
++  };
++
++  Empty.prototype.jasmineToString = function() {
++    return '<jasmine.empty>';
++  };
++
++  return Empty;
++};
++
++getJasmineRequireObj().Falsy = function(j$) {
++  function Falsy() {}
++
++  Falsy.prototype.asymmetricMatch = function(other) {
++    return !other;
++  };
++
++  Falsy.prototype.jasmineToString = function() {
++    return '<jasmine.falsy>';
++  };
++
++  return Falsy;
++};
++
++getJasmineRequireObj().MapContaining = function(j$) {
++  function MapContaining(sample) {
++    if (!j$.isMap(sample)) {
++      throw new Error(
++        'You must provide a map to `mapContaining`, not ' + j$.pp(sample)
++      );
++    }
++
++    this.sample = sample;
++  }
++
++  MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
++    if (!j$.isMap(other)) return false;
++
++    var hasAllMatches = true;
++    j$.util.forEachBreakable(this.sample, function(breakLoop, value, key) {
++      // for each key/value pair in `sample`
++      // there should be at least one pair in `other` whose key and value both match
++      var hasMatch = false;
++      j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
++        if (
++          matchersUtil.equals(oKey, key) &&
++          matchersUtil.equals(oValue, value)
++        ) {
++          hasMatch = true;
++          oBreakLoop();
++        }
++      });
++      if (!hasMatch) {
++        hasAllMatches = false;
++        breakLoop();
++      }
++    });
++
++    return hasAllMatches;
++  };
++
++  MapContaining.prototype.jasmineToString = function(pp) {
++    return '<jasmine.mapContaining(' + pp(this.sample) + ')>';
++  };
++
++  return MapContaining;
++};
++
++getJasmineRequireObj().NotEmpty = function(j$) {
++  function NotEmpty() {}
++
++  NotEmpty.prototype.asymmetricMatch = function(other) {
++    if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
++      return other.length !== 0;
++    }
++
++    if (j$.isMap(other) || j$.isSet(other)) {
++      return other.size !== 0;
++    }
++
++    if (j$.isObject_(other)) {
++      return Object.keys(other).length !== 0;
++    }
++
++    return false;
++  };
++
++  NotEmpty.prototype.jasmineToString = function() {
++    return '<jasmine.notEmpty>';
++  };
++
++  return NotEmpty;
++};
++
++getJasmineRequireObj().ObjectContaining = function(j$) {
++  function ObjectContaining(sample) {
++    this.sample = sample;
++  }
++
++  function getPrototype(obj) {
++    if (Object.getPrototypeOf) {
++      return Object.getPrototypeOf(obj);
++    }
++
++    if (obj.constructor.prototype == obj) {
++      return null;
++    }
++
++    return obj.constructor.prototype;
++  }
++
++  function hasProperty(obj, property) {
++    if (!obj || typeof obj !== 'object') {
++      return false;
++    }
++
++    if (Object.prototype.hasOwnProperty.call(obj, property)) {
++      return true;
++    }
++
++    return hasProperty(getPrototype(obj), property);
++  }
++
++  ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
++    if (typeof this.sample !== 'object') {
++      throw new Error(
++        "You must provide an object to objectContaining, not '" +
++          this.sample +
++          "'."
++      );
++    }
++    if (typeof other !== 'object') {
++      return false;
++    }
++
++    for (var property in this.sample) {
++      if (
++        !hasProperty(other, property) ||
++        !matchersUtil.equals(this.sample[property], other[property])
++      ) {
++        return false;
++      }
++    }
++
++    return true;
++  };
++
++  ObjectContaining.prototype.valuesForDiff_ = function(other, pp) {
++    if (!j$.isObject_(other)) {
++      return {
++        self: this.jasmineToString(pp),
++        other: other
++      };
++    }
++
++    var filteredOther = {};
++    Object.keys(this.sample).forEach(function(k) {
++      // eq short-circuits comparison of objects that have different key sets,
++      // so include all keys even if undefined.
++      filteredOther[k] = other[k];
++    });
++
++    return {
++      self: this.sample,
++      other: filteredOther
++    };
++  };
++
++  ObjectContaining.prototype.jasmineToString = function(pp) {
++    return '<jasmine.objectContaining(' + pp(this.sample) + ')>';
++  };
++
++  return ObjectContaining;
++};
++
++getJasmineRequireObj().SetContaining = function(j$) {
++  function SetContaining(sample) {
++    if (!j$.isSet(sample)) {
++      throw new Error(
++        'You must provide a set to `setContaining`, not ' + j$.pp(sample)
++      );
++    }
++
++    this.sample = sample;
++  }
++
++  SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
++    if (!j$.isSet(other)) return false;
++
++    var hasAllMatches = true;
++    j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
++      // for each item in `sample` there should be at least one matching item in `other`
++      // (not using `matchersUtil.contains` because it compares set members by reference,
++      // not by deep value equality)
++      var hasMatch = false;
++      j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
++        if (matchersUtil.equals(oItem, item)) {
++          hasMatch = true;
++          oBreakLoop();
++        }
++      });
++      if (!hasMatch) {
++        hasAllMatches = false;
++        breakLoop();
++      }
++    });
++
++    return hasAllMatches;
++  };
++
++  SetContaining.prototype.jasmineToString = function(pp) {
++    return '<jasmine.setContaining(' + pp(this.sample) + ')>';
++  };
++
++  return SetContaining;
++};
++
++getJasmineRequireObj().StringContaining = function(j$) {
++  function StringContaining(expected) {
++    if (!j$.isString_(expected)) {
++      throw new Error('Expected is not a String');
++    }
++
++    this.expected = expected;
++  }
++
++  StringContaining.prototype.asymmetricMatch = function(other) {
++    if (!j$.isString_(other)) {
++      // Arrays, etc. don't match no matter what their indexOf returns.
++      return false;
++    }
++
++    return other.indexOf(this.expected) !== -1;
++  };
++
++  StringContaining.prototype.jasmineToString = function() {
++    return '<jasmine.stringContaining("' + this.expected + '")>';
++  };
++
++  return StringContaining;
++};
++
++getJasmineRequireObj().StringMatching = function(j$) {
++  function StringMatching(expected) {
++    if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
++      throw new Error('Expected is not a String or a RegExp');
++    }
++
++    this.regexp = new RegExp(expected);
++  }
++
++  StringMatching.prototype.asymmetricMatch = function(other) {
++    return this.regexp.test(other);
++  };
++
++  StringMatching.prototype.jasmineToString = function() {
++    return '<jasmine.stringMatching(' + this.regexp + ')>';
++  };
++
++  return StringMatching;
++};
++
++getJasmineRequireObj().Truthy = function(j$) {
++  function Truthy() {}
++
++  Truthy.prototype.asymmetricMatch = function(other) {
++    return !!other;
++  };
++
++  Truthy.prototype.jasmineToString = function() {
++    return '<jasmine.truthy>';
++  };
++
++  return Truthy;
++};
++
++getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
++  /*
++    Older versions of Jasmine passed an array of custom equality testers as the
++    second argument to each asymmetric equality tester's `asymmetricMatch`
++    method. Newer versions will pass a `MatchersUtil` instance. The
++    asymmetricEqualityTesterArgCompatShim allows for a graceful migration from
++    the old interface to the new by "being" both an array of custom equality
++    testers and a `MatchersUtil` at the same time.
++
++    This code should be removed in the next major release.
++   */
++
++  var likelyArrayProps = [
++    'concat',
++    'constructor',
++    'copyWithin',
++    'entries',
++    'every',
++    'fill',
++    'filter',
++    'find',
++    'findIndex',
++    'flat',
++    'flatMap',
++    'forEach',
++    'includes',
++    'indexOf',
++    'join',
++    'keys',
++    'lastIndexOf',
++    'length',
++    'map',
++    'pop',
++    'push',
++    'reduce',
++    'reduceRight',
++    'reverse',
++    'shift',
++    'slice',
++    'some',
++    'sort',
++    'splice',
++    'toLocaleString',
++    'toSource',
++    'toString',
++    'unshift',
++    'values'
++  ];
++
++  function asymmetricEqualityTesterArgCompatShim(
++    matchersUtil,
++    customEqualityTesters
++  ) {
++    var self = Object.create(matchersUtil),
++      props,
++      i,
++      k;
++
++    copy(self, customEqualityTesters, 'length');
++
++    for (i = 0; i < customEqualityTesters.length; i++) {
++      copy(self, customEqualityTesters, i);
++    }
++
++    var props = arrayProps();
++
++    for (i = 0; i < props.length; i++) {
++      k = props[i];
++      // Skip length (dealt with above), and anything that collides with
++      // MatchesUtil e.g. an Array.prototype.contains method added by user code
++      if (k !== 'length' && !self[k]) {
++        copy(self, Array.prototype, k);
++      }
++    }
++
++    return self;
++  }
++
++  function copy(dest, src, propName) {
++    Object.defineProperty(dest, propName, {
++      get: function() {
++        return src[propName];
++      }
++    });
++  }
++
++  function arrayProps() {
++    var props, a, k;
++
++    if (!Object.getOwnPropertyDescriptors) {
++      return likelyArrayProps.filter(function(k) {
++        return Array.prototype.hasOwnProperty(k);
++      });
++    }
++
++    props = Object.getOwnPropertyDescriptors(Array.prototype); // eslint-disable-line compat/compat
++    a = [];
++
++    for (k in props) {
++      a.push(k);
++    }
++
++    return a;
++  }
++
++  return asymmetricEqualityTesterArgCompatShim;
++};
++
++getJasmineRequireObj().CallTracker = function(j$) {
++  /**
++   * @namespace Spy#calls
++   * @since 2.0.0
++   */
++  function CallTracker() {
++    var calls = [];
++    var opts = {};
++
++    this.track = function(context) {
++      if (opts.cloneArgs) {
++        context.args = j$.util.cloneArgs(context.args);
++      }
++      calls.push(context);
++    };
++
++    /**
++     * Check whether this spy has been invoked.
++     * @name Spy#calls#any
++     * @since 2.0.0
++     * @function
++     * @return {Boolean}
++     */
++    this.any = function() {
++      return !!calls.length;
++    };
++
++    /**
++     * Get the number of invocations of this spy.
++     * @name Spy#calls#count
++     * @since 2.0.0
++     * @function
++     * @return {Integer}
++     */
++    this.count = function() {
++      return calls.length;
++    };
++
++    /**
++     * Get the arguments that were passed to a specific invocation of this spy.
++     * @name Spy#calls#argsFor
++     * @since 2.0.0
++     * @function
++     * @param {Integer} index The 0-based invocation index.
++     * @return {Array}
++     */
++    this.argsFor = function(index) {
++      var call = calls[index];
++      return call ? call.args : [];
++    };
++
++    /**
++     * Get the "this" object that was passed to a specific invocation of this spy.
++     * @name Spy#calls#thisFor
++     * @since 3.8.0
++     * @function
++     * @param {Integer} index The 0-based invocation index.
++     * @return {Object?}
++     */
++    this.thisFor = function(index) {
++      var call = calls[index];
++      return call ? call.object : undefined;
++    };
++
++    /**
++     * Get the raw calls array for this spy.
++     * @name Spy#calls#all
++     * @since 2.0.0
++     * @function
++     * @return {Spy.callData[]}
++     */
++    this.all = function() {
++      return calls;
++    };
++
++    /**
++     * Get all of the arguments for each invocation of this spy in the order they were received.
++     * @name Spy#calls#allArgs
++     * @since 2.0.0
++     * @function
++     * @return {Array}
++     */
++    this.allArgs = function() {
++      var callArgs = [];
++      for (var i = 0; i < calls.length; i++) {
++        callArgs.push(calls[i].args);
++      }
++
++      return callArgs;
++    };
++
++    /**
++     * Get the first invocation of this spy.
++     * @name Spy#calls#first
++     * @since 2.0.0
++     * @function
++     * @return {ObjecSpy.callData}
++     */
++    this.first = function() {
++      return calls[0];
++    };
++
++    /**
++     * Get the most recent invocation of this spy.
++     * @name Spy#calls#mostRecent
++     * @since 2.0.0
++     * @function
++     * @return {ObjecSpy.callData}
++     */
++    this.mostRecent = function() {
++      return calls[calls.length - 1];
++    };
++
++    /**
++     * Reset this spy as if it has never been called.
++     * @name Spy#calls#reset
++     * @since 2.0.0
++     * @function
++     */
++    this.reset = function() {
++      calls = [];
++    };
++
++    /**
++     * Set this spy to do a shallow clone of arguments passed to each invocation.
++     * @name Spy#calls#saveArgumentsByValue
++     * @since 2.5.0
++     * @function
++     */
++    this.saveArgumentsByValue = function() {
++      opts.cloneArgs = true;
++    };
++  }
++
++  return CallTracker;
++};
++
++getJasmineRequireObj().clearStack = function(j$) {
++  var maxInlineCallCount = 10;
++
++  function messageChannelImpl(global, setTimeout) {
++    var channel = new global.MessageChannel(),
++      head = {},
++      tail = head;
++
++    var taskRunning = false;
++    channel.port1.onmessage = function() {
++      head = head.next;
++      var task = head.task;
++      delete head.task;
++
++      if (taskRunning) {
++        global.setTimeout(task, 0);
++      } else {
++        try {
++          taskRunning = true;
++          task();
++        } finally {
++          taskRunning = false;
++        }
++      }
++    };
++
++    var currentCallCount = 0;
++    return function clearStack(fn) {
++      currentCallCount++;
++
++      if (currentCallCount < maxInlineCallCount) {
++        tail = tail.next = { task: fn };
++        channel.port2.postMessage(0);
++      } else {
++        currentCallCount = 0;
++        setTimeout(fn);
++      }
++    };
++  }
++
++  function getClearStack(global) {
++    var currentCallCount = 0;
++    var realSetTimeout = global.setTimeout;
++    var setTimeoutImpl = function clearStack(fn) {
++      Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
++    };
++
++    if (j$.isFunction_(global.setImmediate)) {
++      var realSetImmediate = global.setImmediate;
++      return function(fn) {
++        currentCallCount++;
++
++        if (currentCallCount < maxInlineCallCount) {
++          realSetImmediate(fn);
++        } else {
++          currentCallCount = 0;
++
++          setTimeoutImpl(fn);
++        }
++      };
++    } else if (!j$.util.isUndefined(global.MessageChannel)) {
++      return messageChannelImpl(global, setTimeoutImpl);
++    } else {
++      return setTimeoutImpl;
++    }
++  }
++
++  return getClearStack;
++};
++
++getJasmineRequireObj().Clock = function() {
++  /* global process */
++  var NODE_JS =
++    typeof process !== 'undefined' &&
++    process.versions &&
++    typeof process.versions.node === 'string';
++
++  /**
++   * @class Clock
++   * @since 1.3.0
++   * @classdesc Jasmine's mock clock is used when testing time dependent code.<br>
++   * _Note:_ Do not construct this directly. You can get the current clock with
++   * {@link jasmine.clock}.
++   * @hideconstructor
++   */
++  function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
++    var self = this,
++      realTimingFunctions = {
++        setTimeout: global.setTimeout,
++        clearTimeout: global.clearTimeout,
++        setInterval: global.setInterval,
++        clearInterval: global.clearInterval
++      },
++      fakeTimingFunctions = {
++        setTimeout: setTimeout,
++        clearTimeout: clearTimeout,
++        setInterval: setInterval,
++        clearInterval: clearInterval
++      },
++      installed = false,
++      delayedFunctionScheduler,
++      timer;
++
++    self.FakeTimeout = FakeTimeout;
++
++    /**
++     * Install the mock clock over the built-in methods.
++     * @name Clock#install
++     * @since 2.0.0
++     * @function
++     * @return {Clock}
++     */
++    self.install = function() {
++      if (!originalTimingFunctionsIntact()) {
++        throw new Error(
++          'Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?'
++        );
++      }
++      replace(global, fakeTimingFunctions);
++      timer = fakeTimingFunctions;
++      delayedFunctionScheduler = delayedFunctionSchedulerFactory();
++      installed = true;
++
++      return self;
++    };
++
++    /**
++     * Uninstall the mock clock, returning the built-in methods to their places.
++     * @name Clock#uninstall
++     * @since 2.0.0
++     * @function
++     */
++    self.uninstall = function() {
++      delayedFunctionScheduler = null;
++      mockDate.uninstall();
++      replace(global, realTimingFunctions);
++
++      timer = realTimingFunctions;
++      installed = false;
++    };
++
++    /**
++     * Execute a function with a mocked Clock
++     *
++     * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
++     * @name Clock#withMock
++     * @since 2.3.0
++     * @function
++     * @param {Function} closure The function to be called.
++     */
++    self.withMock = function(closure) {
++      this.install();
++      try {
++        closure();
++      } finally {
++        this.uninstall();
++      }
++    };
++
++    /**
++     * Instruct the installed Clock to also mock the date returned by `new Date()`
++     * @name Clock#mockDate
++     * @since 2.1.0
++     * @function
++     * @param {Date} [initialDate=now] The `Date` to provide.
++     */
++    self.mockDate = function(initialDate) {
++      mockDate.install(initialDate);
++    };
++
++    self.setTimeout = function(fn, delay, params) {
++      return Function.prototype.apply.apply(timer.setTimeout, [
++        global,
++        arguments
++      ]);
++    };
++
++    self.setInterval = function(fn, delay, params) {
++      return Function.prototype.apply.apply(timer.setInterval, [
++        global,
++        arguments
++      ]);
++    };
++
++    self.clearTimeout = function(id) {
++      return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
++    };
++
++    self.clearInterval = function(id) {
++      return Function.prototype.call.apply(timer.clearInterval, [global, id]);
++    };
++
++    /**
++     * Tick the Clock forward, running any enqueued timeouts along the way
++     * @name Clock#tick
++     * @since 1.3.0
++     * @function
++     * @param {int} millis The number of milliseconds to tick.
++     */
++    self.tick = function(millis) {
++      if (installed) {
++        delayedFunctionScheduler.tick(millis, function(millis) {
++          mockDate.tick(millis);
++        });
++      } else {
++        throw new Error(
++          'Mock clock is not installed, use jasmine.clock().install()'
++        );
++      }
++    };
++
++    return self;
++
++    function originalTimingFunctionsIntact() {
++      return (
++        global.setTimeout === realTimingFunctions.setTimeout &&
++        global.clearTimeout === realTimingFunctions.clearTimeout &&
++        global.setInterval === realTimingFunctions.setInterval &&
++        global.clearInterval === realTimingFunctions.clearInterval
++      );
++    }
++
++    function replace(dest, source) {
++      for (var prop in source) {
++        dest[prop] = source[prop];
++      }
++    }
++
++    function setTimeout(fn, delay) {
++      if (!NODE_JS) {
++        return delayedFunctionScheduler.scheduleFunction(
++          fn,
++          delay,
++          argSlice(arguments, 2)
++        );
++      }
++
++      var timeout = new FakeTimeout();
++
++      delayedFunctionScheduler.scheduleFunction(
++        fn,
++        delay,
++        argSlice(arguments, 2),
++        false,
++        timeout
++      );
++
++      return timeout;
++    }
++
++    function clearTimeout(id) {
++      return delayedFunctionScheduler.removeFunctionWithId(id);
++    }
++
++    function setInterval(fn, interval) {
++      if (!NODE_JS) {
++        return delayedFunctionScheduler.scheduleFunction(
++          fn,
++          interval,
++          argSlice(arguments, 2),
++          true
++        );
++      }
++
++      var timeout = new FakeTimeout();
++
++      delayedFunctionScheduler.scheduleFunction(
++        fn,
++        interval,
++        argSlice(arguments, 2),
++        true,
++        timeout
++      );
++
++      return timeout;
++    }
++
++    function clearInterval(id) {
++      return delayedFunctionScheduler.removeFunctionWithId(id);
++    }
++
++    function argSlice(argsObj, n) {
++      return Array.prototype.slice.call(argsObj, n);
++    }
++  }
++
++  /**
++   * Mocks Node.js Timeout class
++   */
++  function FakeTimeout() {}
++
++  FakeTimeout.prototype.ref = function() {
++    return this;
++  };
++
++  FakeTimeout.prototype.unref = function() {
++    return this;
++  };
++
++  return Clock;
++};
++
++getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
++  function DelayedFunctionScheduler() {
++    var self = this;
++    var scheduledLookup = [];
++    var scheduledFunctions = {};
++    var currentTime = 0;
++    var delayedFnCount = 0;
++    var deletedKeys = [];
++
++    self.tick = function(millis, tickDate) {
++      millis = millis || 0;
++      var endTime = currentTime + millis;
++
++      runScheduledFunctions(endTime, tickDate);
++      currentTime = endTime;
++    };
++
++    self.scheduleFunction = function(
++      funcToCall,
++      millis,
++      params,
++      recurring,
++      timeoutKey,
++      runAtMillis
++    ) {
++      var f;
++      if (typeof funcToCall === 'string') {
++        /* jshint evil: true */
++        f = function() {
++          return eval(funcToCall);
++        };
++        /* jshint evil: false */
++      } else {
++        f = funcToCall;
++      }
++
++      millis = millis || 0;
++      timeoutKey = timeoutKey || ++delayedFnCount;
++      runAtMillis = runAtMillis || currentTime + millis;
++
++      var funcToSchedule = {
++        runAtMillis: runAtMillis,
++        funcToCall: f,
++        recurring: recurring,
++        params: params,
++        timeoutKey: timeoutKey,
++        millis: millis
++      };
++
++      if (runAtMillis in scheduledFunctions) {
++        scheduledFunctions[runAtMillis].push(funcToSchedule);
++      } else {
++        scheduledFunctions[runAtMillis] = [funcToSchedule];
++        scheduledLookup.push(runAtMillis);
++        scheduledLookup.sort(function(a, b) {
++          return a - b;
++        });
++      }
++
++      return timeoutKey;
++    };
++
++    self.removeFunctionWithId = function(timeoutKey) {
++      deletedKeys.push(timeoutKey);
++
++      for (var runAtMillis in scheduledFunctions) {
++        var funcs = scheduledFunctions[runAtMillis];
++        var i = indexOfFirstToPass(funcs, function(func) {
++          return func.timeoutKey === timeoutKey;
++        });
++
++        if (i > -1) {
++          if (funcs.length === 1) {
++            delete scheduledFunctions[runAtMillis];
++            deleteFromLookup(runAtMillis);
++          } else {
++            funcs.splice(i, 1);
++          }
++
++          // intervals get rescheduled when executed, so there's never more
++          // than a single scheduled function with a given timeoutKey
++          break;
++        }
++      }
++    };
++
++    return self;
++
++    function indexOfFirstToPass(array, testFn) {
++      var index = -1;
++
++      for (var i = 0; i < array.length; ++i) {
++        if (testFn(array[i])) {
++          index = i;
++          break;
++        }
++      }
++
++      return index;
++    }
++
++    function deleteFromLookup(key) {
++      var value = Number(key);
++      var i = indexOfFirstToPass(scheduledLookup, function(millis) {
++        return millis === value;
++      });
++
++      if (i > -1) {
++        scheduledLookup.splice(i, 1);
++      }
++    }
++
++    function reschedule(scheduledFn) {
++      self.scheduleFunction(
++        scheduledFn.funcToCall,
++        scheduledFn.millis,
++        scheduledFn.params,
++        true,
++        scheduledFn.timeoutKey,
++        scheduledFn.runAtMillis + scheduledFn.millis
++      );
++    }
++
++    function forEachFunction(funcsToRun, callback) {
++      for (var i = 0; i < funcsToRun.length; ++i) {
++        callback(funcsToRun[i]);
++      }
++    }
++
++    function runScheduledFunctions(endTime, tickDate) {
++      tickDate = tickDate || function() {};
++      if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
++        tickDate(endTime - currentTime);
++        return;
++      }
++
++      do {
++        deletedKeys = [];
++        var newCurrentTime = scheduledLookup.shift();
++        tickDate(newCurrentTime - currentTime);
++
++        currentTime = newCurrentTime;
++
++        var funcsToRun = scheduledFunctions[currentTime];
++
++        delete scheduledFunctions[currentTime];
++
++        forEachFunction(funcsToRun, function(funcToRun) {
++          if (funcToRun.recurring) {
++            reschedule(funcToRun);
++          }
++        });
++
++        forEachFunction(funcsToRun, function(funcToRun) {
++          if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) {
++            // skip a timeoutKey deleted whilst we were running
++            return;
++          }
++          funcToRun.funcToCall.apply(null, funcToRun.params || []);
++        });
++        deletedKeys = [];
++      } while (
++        scheduledLookup.length > 0 &&
++        // checking first if we're out of time prevents setTimeout(0)
++        // scheduled in a funcToRun from forcing an extra iteration
++        currentTime !== endTime &&
++        scheduledLookup[0] <= endTime
++      );
++
++      // ran out of functions to call, but still time left on the clock
++      if (currentTime !== endTime) {
++        tickDate(endTime - currentTime);
++      }
++    }
++  }
++
++  return DelayedFunctionScheduler;
++};
++
++getJasmineRequireObj().errors = function() {
++  function ExpectationFailed() {}
++
++  ExpectationFailed.prototype = new Error();
++  ExpectationFailed.prototype.constructor = ExpectationFailed;
++
++  return {
++    ExpectationFailed: ExpectationFailed
++  };
++};
++
++getJasmineRequireObj().ExceptionFormatter = function(j$) {
++  var ignoredProperties = [
++    'name',
++    'message',
++    'stack',
++    'fileName',
++    'sourceURL',
++    'line',
++    'lineNumber',
++    'column',
++    'description',
++    'jasmineMessage'
++  ];
++
++  function ExceptionFormatter(options) {
++    var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile();
++    this.message = function(error) {
++      var message = '';
++
++      if (error.jasmineMessage) {
++        message += error.jasmineMessage;
++      } else if (error.name && error.message) {
++        message += error.name + ': ' + error.message;
++      } else if (error.message) {
++        message += error.message;
++      } else {
++        message += error.toString() + ' thrown';
++      }
++
++      if (error.fileName || error.sourceURL) {
++        message += ' in ' + (error.fileName || error.sourceURL);
++      }
++
++      if (error.line || error.lineNumber) {
++        message += ' (line ' + (error.line || error.lineNumber) + ')';
++      }
++
++      return message;
++    };
++
++    this.stack = function(error) {
++      if (!error || !error.stack) {
++        return null;
++      }
++
++      var stackTrace = new j$.StackTrace(error);
++      var lines = filterJasmine(stackTrace);
++      var result = '';
++
++      if (stackTrace.message) {
++        lines.unshift(stackTrace.message);
++      }
++
++      result += formatProperties(error);
++      result += lines.join('\n');
++
++      return result;
++    };
++
++    function filterJasmine(stackTrace) {
++      var result = [],
++        jasmineMarker =
++          stackTrace.style === 'webkit' ? '<Jasmine>' : '    at <Jasmine>';
++
++      stackTrace.frames.forEach(function(frame) {
++        if (frame.file !== jasmineFile) {
++          result.push(frame.raw);
++        } else if (result[result.length - 1] !== jasmineMarker) {
++          result.push(jasmineMarker);
++        }
++      });
++
++      return result;
++    }
++
++    function formatProperties(error) {
++      if (!(error instanceof Object)) {
++        return;
++      }
++
++      var result = {};
++      var empty = true;
++
++      for (var prop in error) {
++        if (j$.util.arrayContains(ignoredProperties, prop)) {
++          continue;
++        }
++        result[prop] = error[prop];
++        empty = false;
++      }
++
++      if (!empty) {
++        return 'error properties: ' + j$.pp(result) + '\n';
++      }
++
++      return '';
++    }
++  }
++
++  return ExceptionFormatter;
++};
++
++getJasmineRequireObj().Expectation = function(j$) {
++  /**
++   * Matchers that come with Jasmine out of the box.
++   * @namespace matchers
++   */
++  function Expectation(options) {
++    this.expector = new j$.Expector(options);
++
++    var customMatchers = options.customMatchers || {};
++    for (var matcherName in customMatchers) {
++      this[matcherName] = wrapSyncCompare(
++        matcherName,
++        customMatchers[matcherName]
++      );
++    }
++  }
++
++  /**
++   * Add some context for an {@link expect}
++   * @function
++   * @name matchers#withContext
++   * @since 3.3.0
++   * @param {String} message - Additional context to show when the matcher fails
++   * @return {matchers}
++   */
++  Expectation.prototype.withContext = function withContext(message) {
++    return addFilter(this, new ContextAddingFilter(message));
++  };
++
++  /**
++   * Invert the matcher following this {@link expect}
++   * @member
++   * @name matchers#not
++   * @since 1.3.0
++   * @type {matchers}
++   * @example
++   * expect(something).not.toBe(true);
++   */
++  Object.defineProperty(Expectation.prototype, 'not', {
++    get: function() {
++      return addFilter(this, syncNegatingFilter);
++    }
++  });
++
++  /**
++   * Asynchronous matchers that operate on an actual value which is a promise,
++   * and return a promise.
++   *
++   * Most async matchers will wait indefinitely for the promise to be resolved
++   * or rejected, resulting in a spec timeout if that never happens. If you
++   * expect that the promise will already be resolved or rejected at the time
++   * the matcher is called, you can use the {@link async-matchers#already}
++   * modifier to get a faster failure with a more helpful message.
++   *
++   * Note: Specs must await the result of each async matcher, return the
++   * promise returned by the matcher, or return a promise that's derived from
++   * the one returned by the matcher. Otherwise the matcher will not be
++   * evaluated before the spec completes.
++   *
++   * @example
++   * // Good
++   * await expectAsync(aPromise).toBeResolved();
++   * @example
++   * // Good
++   * return expectAsync(aPromise).toBeResolved();
++   * @example
++   * // Good
++   * return expectAsync(aPromise).toBeResolved()
++   *  .then(function() {
++   *    // more spec code
++   *  });
++   * @example
++   * // Bad
++   * expectAsync(aPromise).toBeResolved();
++   * @namespace async-matchers
++   */
++  function AsyncExpectation(options) {
++    var global = options.global || j$.getGlobal();
++    this.expector = new j$.Expector(options);
++
++    if (!global.Promise) {
++      throw new Error(
++        'expectAsync is unavailable because the environment does not support promises.'
++      );
++    }
++
++    var customAsyncMatchers = options.customAsyncMatchers || {};
++    for (var matcherName in customAsyncMatchers) {
++      this[matcherName] = wrapAsyncCompare(
++        matcherName,
++        customAsyncMatchers[matcherName]
++      );
++    }
++  }
++
++  /**
++   * Add some context for an {@link expectAsync}
++   * @function
++   * @name async-matchers#withContext
++   * @since 3.3.0
++   * @param {String} message - Additional context to show when the async matcher fails
++   * @return {async-matchers}
++   */
++  AsyncExpectation.prototype.withContext = function withContext(message) {
++    return addFilter(this, new ContextAddingFilter(message));
++  };
++
++  /**
++   * Invert the matcher following this {@link expectAsync}
++   * @member
++   * @name async-matchers#not
++   * @type {async-matchers}
++   * @example
++   * await expectAsync(myPromise).not.toBeResolved();
++   * @example
++   * return expectAsync(myPromise).not.toBeResolved();
++   */
++  Object.defineProperty(AsyncExpectation.prototype, 'not', {
++    get: function() {
++      return addFilter(this, asyncNegatingFilter);
++    }
++  });
++
++  /**
++   * Fail as soon as possible if the actual is pending.
++   * Otherwise evaluate the matcher.
++   * @member
++   * @name async-matchers#already
++   * @since 3.8.0
++   * @type {async-matchers}
++   * @example
++   * await expectAsync(myPromise).already.toBeResolved();
++   * @example
++   * return expectAsync(myPromise).already.toBeResolved();
++   */
++  Object.defineProperty(AsyncExpectation.prototype, 'already', {
++    get: function() {
++      return addFilter(this, expectSettledPromiseFilter);
++    }
++  });
++
++  function wrapSyncCompare(name, matcherFactory) {
++    return function() {
++      var result = this.expector.compare(name, matcherFactory, arguments);
++      this.expector.processResult(result);
++    };
++  }
++
++  function wrapAsyncCompare(name, matcherFactory) {
++    return function() {
++      var self = this;
++
++      // Capture the call stack here, before we go async, so that it will contain
++      // frames that are relevant to the user instead of just parts of Jasmine.
++      var errorForStack = j$.util.errorWithStack();
++
++      return this.expector
++        .compare(name, matcherFactory, arguments)
++        .then(function(result) {
++          self.expector.processResult(result, errorForStack);
++        });
++    };
++  }
++
++  function addCoreMatchers(prototype, matchers, wrapper) {
++    for (var matcherName in matchers) {
++      var matcher = matchers[matcherName];
++      prototype[matcherName] = wrapper(matcherName, matcher);
++    }
++  }
++
++  function addFilter(source, filter) {
++    var result = Object.create(source);
++    result.expector = source.expector.addFilter(filter);
++    return result;
++  }
++
++  function negatedFailureMessage(result, matcherName, args, matchersUtil) {
++    if (result.message) {
++      if (j$.isFunction_(result.message)) {
++        return result.message();
++      } else {
++        return result.message;
++      }
++    }
++
++    args = args.slice();
++    args.unshift(true);
++    args.unshift(matcherName);
++    return matchersUtil.buildFailureMessage.apply(matchersUtil, args);
++  }
++
++  function negate(result) {
++    result.pass = !result.pass;
++    return result;
++  }
++
++  var syncNegatingFilter = {
++    selectComparisonFunc: function(matcher) {
++      function defaultNegativeCompare() {
++        return negate(matcher.compare.apply(null, arguments));
++      }
++
++      return matcher.negativeCompare || defaultNegativeCompare;
++    },
++    buildFailureMessage: negatedFailureMessage
++  };
++
++  var asyncNegatingFilter = {
++    selectComparisonFunc: function(matcher) {
++      function defaultNegativeCompare() {
++        return matcher.compare.apply(this, arguments).then(negate);
++      }
++
++      return matcher.negativeCompare || defaultNegativeCompare;
++    },
++    buildFailureMessage: negatedFailureMessage
++  };
++
++  var expectSettledPromiseFilter = {
++    selectComparisonFunc: function(matcher) {
++      return function(actual) {
++        var matcherArgs = arguments;
++
++        return j$.isPending_(actual).then(function(isPending) {
++          if (isPending) {
++            return {
++              pass: false,
++              message:
++                'Expected a promise to be settled (via ' +
++                'expectAsync(...).already) but it was pending.'
++            };
++          } else {
++            return matcher.compare.apply(null, matcherArgs);
++          }
++        });
++      };
++    }
++  };
++
++  function ContextAddingFilter(message) {
++    this.message = message;
++  }
++
++  ContextAddingFilter.prototype.modifyFailureMessage = function(msg) {
++    var nl = msg.indexOf('\n');
++
++    if (nl === -1) {
++      return this.message + ': ' + msg;
++    } else {
++      return this.message + ':\n' + indent(msg);
++    }
++  };
++
++  function indent(s) {
++    return s.replace(/^/gm, '    ');
++  }
++
++  return {
++    factory: function(options) {
++      return new Expectation(options || {});
++    },
++    addCoreMatchers: function(matchers) {
++      addCoreMatchers(Expectation.prototype, matchers, wrapSyncCompare);
++    },
++    asyncFactory: function(options) {
++      return new AsyncExpectation(options || {});
++    },
++    addAsyncCoreMatchers: function(matchers) {
++      addCoreMatchers(AsyncExpectation.prototype, matchers, wrapAsyncCompare);
++    }
++  };
++};
++
++getJasmineRequireObj().ExpectationFilterChain = function() {
++  function ExpectationFilterChain(maybeFilter, prev) {
++    this.filter_ = maybeFilter;
++    this.prev_ = prev;
++  }
++
++  ExpectationFilterChain.prototype.addFilter = function(filter) {
++    return new ExpectationFilterChain(filter, this);
++  };
++
++  ExpectationFilterChain.prototype.selectComparisonFunc = function(matcher) {
++    return this.callFirst_('selectComparisonFunc', arguments).result;
++  };
++
++  ExpectationFilterChain.prototype.buildFailureMessage = function(
++    result,
++    matcherName,
++    args,
++    matchersUtil
++  ) {
++    return this.callFirst_('buildFailureMessage', arguments).result;
++  };
++
++  ExpectationFilterChain.prototype.modifyFailureMessage = function(msg) {
++    var result = this.callFirst_('modifyFailureMessage', arguments).result;
++    return result || msg;
++  };
++
++  ExpectationFilterChain.prototype.callFirst_ = function(fname, args) {
++    var prevResult;
++
++    if (this.prev_) {
++      prevResult = this.prev_.callFirst_(fname, args);
++
++      if (prevResult.found) {
++        return prevResult;
++      }
++    }
++
++    if (this.filter_ && this.filter_[fname]) {
++      return {
++        found: true,
++        result: this.filter_[fname].apply(this.filter_, args)
++      };
++    }
++
++    return { found: false };
++  };
++
++  return ExpectationFilterChain;
++};
++
++//TODO: expectation result may make more sense as a presentation of an expectation.
++getJasmineRequireObj().buildExpectationResult = function(j$) {
++  function buildExpectationResult(options) {
++    var messageFormatter = options.messageFormatter || function() {},
++      stackFormatter = options.stackFormatter || function() {};
++
++    /**
++     * @typedef Expectation
++     * @property {String} matcherName - The name of the matcher that was executed for this expectation.
++     * @property {String} message - The failure message for the expectation.
++     * @property {String} stack - The stack trace for the failure if available.
++     * @property {Boolean} passed - Whether the expectation passed or failed.
++     * @property {Object} expected - If the expectation failed, what was the expected value.
++     * @property {Object} actual - If the expectation failed, what actual value was produced.
++     */
++    var result = {
++      matcherName: options.matcherName,
++      message: message(),
++      stack: stack(),
++      passed: options.passed
++    };
++
++    if (!result.passed) {
++      result.expected = options.expected;
++      result.actual = options.actual;
++
++      if (options.error && !j$.isString_(options.error)) {
++        if ('code' in options.error) {
++          result.code = options.error.code;
++        }
++
++        if (
++          options.error.code === 'ERR_ASSERTION' &&
++          options.expected === '' &&
++          options.actual === ''
++        ) {
++          result.expected = options.error.expected;
++          result.actual = options.error.actual;
++          result.matcherName = 'assert ' + options.error.operator;
++        }
++      }
++    }
++
++    return result;
++
++    function message() {
++      if (options.passed) {
++        return 'Passed.';
++      } else if (options.message) {
++        return options.message;
++      } else if (options.error) {
++        return messageFormatter(options.error);
++      }
++      return '';
++    }
++
++    function stack() {
++      if (options.passed) {
++        return '';
++      }
++
++      var error = options.error;
++      if (!error) {
++        if (options.errorForStack) {
++          error = options.errorForStack;
++        } else if (options.stack) {
++          error = options;
++        } else {
++          try {
++            throw new Error(message());
++          } catch (e) {
++            error = e;
++          }
++        }
++      }
++      return stackFormatter(error);
++    }
++  }
++
++  return buildExpectationResult;
++};
++
++getJasmineRequireObj().Expector = function(j$) {
++  function Expector(options) {
++    this.matchersUtil = options.matchersUtil || {
++      buildFailureMessage: function() {}
++    };
++    this.customEqualityTesters = options.customEqualityTesters || [];
++    this.actual = options.actual;
++    this.addExpectationResult = options.addExpectationResult || function() {};
++    this.filters = new j$.ExpectationFilterChain();
++  }
++
++  Expector.prototype.instantiateMatcher = function(
++    matcherName,
++    matcherFactory,
++    args
++  ) {
++    this.matcherName = matcherName;
++    this.args = Array.prototype.slice.call(args, 0);
++    this.expected = this.args.slice(0);
++
++    this.args.unshift(this.actual);
++
++    var matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
++    var comparisonFunc = this.filters.selectComparisonFunc(matcher);
++    return comparisonFunc || matcher.compare;
++  };
++
++  Expector.prototype.buildMessage = function(result) {
++    var self = this;
++
++    if (result.pass) {
++      return '';
++    }
++
++    var msg = this.filters.buildFailureMessage(
++      result,
++      this.matcherName,
++      this.args,
++      this.matchersUtil,
++      defaultMessage
++    );
++    return this.filters.modifyFailureMessage(msg || defaultMessage());
++
++    function defaultMessage() {
++      if (!result.message) {
++        var args = self.args.slice();
++        args.unshift(false);
++        args.unshift(self.matcherName);
++        return self.matchersUtil.buildFailureMessage.apply(
++          self.matchersUtil,
++          args
++        );
++      } else if (j$.isFunction_(result.message)) {
++        return result.message();
++      } else {
++        return result.message;
++      }
++    }
++  };
++
++  Expector.prototype.compare = function(matcherName, matcherFactory, args) {
++    var matcherCompare = this.instantiateMatcher(
++      matcherName,
++      matcherFactory,
++      args
++    );
++    return matcherCompare.apply(null, this.args);
++  };
++
++  Expector.prototype.addFilter = function(filter) {
++    var result = Object.create(this);
++    result.filters = this.filters.addFilter(filter);
++    return result;
++  };
++
++  Expector.prototype.processResult = function(result, errorForStack) {
++    var message = this.buildMessage(result);
++
++    if (this.expected.length === 1) {
++      this.expected = this.expected[0];
++    }
++
++    this.addExpectationResult(result.pass, {
++      matcherName: this.matcherName,
++      passed: result.pass,
++      message: message,
++      error: errorForStack ? undefined : result.error,
++      errorForStack: errorForStack || undefined,
++      actual: this.actual,
++      expected: this.expected // TODO: this may need to be arrayified/sliced
++    });
++  };
++
++  return Expector;
++};
++
++getJasmineRequireObj().formatErrorMsg = function() {
++  function generateErrorMsg(domain, usage) {
++    var usageDefinition = usage ? '\nUsage: ' + usage : '';
++
++    return function errorMsg(msg) {
++      return domain + ' : ' + msg + usageDefinition;
++    };
++  }
++
++  return generateErrorMsg;
++};
++
++getJasmineRequireObj().GlobalErrors = function(j$) {
++  function GlobalErrors(global) {
++    var handlers = [];
++    global = global || j$.getGlobal();
++
++    var onerror = function onerror() {
++      var handler = handlers[handlers.length - 1];
++
++      if (handler) {
++        handler.apply(null, Array.prototype.slice.call(arguments, 0));
++      } else {
++        throw arguments[0];
++      }
++    };
++
++    this.originalHandlers = {};
++    this.jasmineHandlers = {};
++    this.installOne_ = function installOne_(errorType, jasmineMessage) {
++      function taggedOnError(error) {
++        var substituteMsg;
++
++        if (j$.isError_(error)) {
++          error.jasmineMessage = jasmineMessage + ': ' + error;
++        } else {
++          if (error) {
++            substituteMsg = jasmineMessage + ': ' + error;
++          } else {
++            substituteMsg = jasmineMessage + ' with no error or message';
++          }
++
++          if (errorType === 'unhandledRejection') {
++            substituteMsg +=
++              '\n' +
++              '(Tip: to get a useful stack trace, use ' +
++              'Promise.reject(new Error(...)) instead of Promise.reject(' +
++              (error ? '...' : '') +
++              ').)';
++          }
++
++          error = new Error(substituteMsg);
++        }
++
++        var handler = handlers[handlers.length - 1];
++
++        if (handler) {
++          handler(error);
++        } else {
++          throw error;
++        }
++      }
++
++      this.originalHandlers[errorType] = global.process.listeners(errorType);
++      this.jasmineHandlers[errorType] = taggedOnError;
++
++      global.process.removeAllListeners(errorType);
++      global.process.on(errorType, taggedOnError);
++
++      this.uninstall = function uninstall() {
++        var errorTypes = Object.keys(this.originalHandlers);
++        for (var iType = 0; iType < errorTypes.length; iType++) {
++          var errorType = errorTypes[iType];
++          global.process.removeListener(
++            errorType,
++            this.jasmineHandlers[errorType]
++          );
++          for (var i = 0; i < this.originalHandlers[errorType].length; i++) {
++            global.process.on(errorType, this.originalHandlers[errorType][i]);
++          }
++          delete this.originalHandlers[errorType];
++          delete this.jasmineHandlers[errorType];
++        }
++      };
++    };
++
++    this.install = function install() {
++      if (
++        global.process &&
++        global.process.listeners &&
++        j$.isFunction_(global.process.on)
++      ) {
++        this.installOne_('uncaughtException', 'Uncaught exception');
++        this.installOne_('unhandledRejection', 'Unhandled promise rejection');
++      } else {
++        var originalHandler = global.onerror;
++        global.onerror = onerror;
++
++        var browserRejectionHandler = function browserRejectionHandler(event) {
++          if (j$.isError_(event.reason)) {
++            event.reason.jasmineMessage =
++              'Unhandled promise rejection: ' + event.reason;
++            global.onerror(event.reason);
++          } else {
++            global.onerror('Unhandled promise rejection: ' + event.reason);
++          }
++        };
++
++        if (global.addEventListener) {
++          global.addEventListener(
++            'unhandledrejection',
++            browserRejectionHandler
++          );
++        }
++
++        this.uninstall = function uninstall() {
++          global.onerror = originalHandler;
++          if (global.removeEventListener) {
++            global.removeEventListener(
++              'unhandledrejection',
++              browserRejectionHandler
++            );
++          }
++        };
++      }
++    };
++
++    this.pushListener = function pushListener(listener) {
++      handlers.push(listener);
++    };
++
++    this.popListener = function popListener(listener) {
++      if (!listener) {
++        throw new Error('popListener expects a listener');
++      }
++
++      handlers.pop();
++    };
++  }
++
++  return GlobalErrors;
++};
++
++/* eslint-disable compat/compat */
++getJasmineRequireObj().toBePending = function(j$) {
++  /**
++   * Expect a promise to be pending, i.e. the promise is neither resolved nor rejected.
++   * @function
++   * @async
++   * @name async-matchers#toBePending
++   * @since 3.6
++   * @example
++   * await expectAsync(aPromise).toBePending();
++   */
++  return function toBePending() {
++    return {
++      compare: function(actual) {
++        if (!j$.isPromiseLike(actual)) {
++          throw new Error('Expected toBePending to be called on a promise.');
++        }
++        var want = {};
++        return Promise.race([actual, Promise.resolve(want)]).then(
++          function(got) {
++            return { pass: want === got };
++          },
++          function() {
++            return { pass: false };
++          }
++        );
++      }
++    };
++  };
++};
++
++getJasmineRequireObj().toBeRejected = function(j$) {
++  /**
++   * Expect a promise to be rejected.
++   * @function
++   * @async
++   * @name async-matchers#toBeRejected
++   * @since 3.1.0
++   * @example
++   * await expectAsync(aPromise).toBeRejected();
++   * @example
++   * return expectAsync(aPromise).toBeRejected();
++   */
++  return function toBeRejected() {
++    return {
++      compare: function(actual) {
++        if (!j$.isPromiseLike(actual)) {
++          throw new Error('Expected toBeRejected to be called on a promise.');
++        }
++        return actual.then(
++          function() {
++            return { pass: false };
++          },
++          function() {
++            return { pass: true };
++          }
++        );
++      }
++    };
++  };
++};
++
++getJasmineRequireObj().toBeRejectedWith = function(j$) {
++  /**
++   * Expect a promise to be rejected with a value equal to the expected, using deep equality comparison.
++   * @function
++   * @async
++   * @name async-matchers#toBeRejectedWith
++   * @since 3.3.0
++   * @param {Object} expected - Value that the promise is expected to be rejected with
++   * @example
++   * await expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
++   * @example
++   * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
++   */
++  return function toBeRejectedWith(matchersUtil) {
++    return {
++      compare: function(actualPromise, expectedValue) {
++        if (!j$.isPromiseLike(actualPromise)) {
++          throw new Error(
++            'Expected toBeRejectedWith to be called on a promise.'
++          );
++        }
++
++        function prefix(passed) {
++          return (
++            'Expected a promise ' +
++            (passed ? 'not ' : '') +
++            'to be rejected with ' +
++            matchersUtil.pp(expectedValue)
++          );
++        }
++
++        return actualPromise.then(
++          function() {
++            return {
++              pass: false,
++              message: prefix(false) + ' but it was resolved.'
++            };
++          },
++          function(actualValue) {
++            if (matchersUtil.equals(actualValue, expectedValue)) {
++              return {
++                pass: true,
++                message: prefix(true) + '.'
++              };
++            } else {
++              return {
++                pass: false,
++                message:
++                  prefix(false) +
++                  ' but it was rejected with ' +
++                  matchersUtil.pp(actualValue) +
++                  '.'
++              };
++            }
++          }
++        );
++      }
++    };
++  };
++};
++
++getJasmineRequireObj().toBeRejectedWithError = function(j$) {
++  /**
++   * Expect a promise to be rejected with a value matched to the expected
++   * @function
++   * @async
++   * @name async-matchers#toBeRejectedWithError
++   * @since 3.5.0
++   * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
++   * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
++   * @example
++   * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, 'Error message');
++   * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, /Error message/);
++   * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError);
++   * await expectAsync(aPromise).toBeRejectedWithError('Error message');
++   * return expectAsync(aPromise).toBeRejectedWithError(/Error message/);
++   */
++  return function toBeRejectedWithError(matchersUtil) {
++    return {
++      compare: function(actualPromise, arg1, arg2) {
++        if (!j$.isPromiseLike(actualPromise)) {
++          throw new Error(
++            'Expected toBeRejectedWithError to be called on a promise.'
++          );
++        }
++
++        var expected = getExpectedFromArgs(arg1, arg2, matchersUtil);
++
++        return actualPromise.then(
++          function() {
++            return {
++              pass: false,
++              message: 'Expected a promise to be rejected but it was resolved.'
++            };
++          },
++          function(actualValue) {
++            return matchError(actualValue, expected, matchersUtil);
++          }
++        );
++      }
++    };
++  };
++
++  function matchError(actual, expected, matchersUtil) {
++    if (!j$.isError_(actual)) {
++      return fail(expected, 'rejected with ' + matchersUtil.pp(actual));
++    }
++
++    if (!(actual instanceof expected.error)) {
++      return fail(
++        expected,
++        'rejected with type ' + j$.fnNameFor(actual.constructor)
++      );
++    }
++
++    var actualMessage = actual.message;
++
++    if (
++      actualMessage === expected.message ||
++      typeof expected.message === 'undefined'
++    ) {
++      return pass(expected);
++    }
++
++    if (
++      expected.message instanceof RegExp &&
++      expected.message.test(actualMessage)
++    ) {
++      return pass(expected);
++    }
++
++    return fail(expected, 'rejected with ' + matchersUtil.pp(actual));
++  }
++
++  function pass(expected) {
++    return {
++      pass: true,
++      message:
++        'Expected a promise not to be rejected with ' +
++        expected.printValue +
++        ', but it was.'
++    };
++  }
++
++  function fail(expected, message) {
++    return {
++      pass: false,
++      message:
++        'Expected a promise to be rejected with ' +
++        expected.printValue +
++        ' but it was ' +
++        message +
++        '.'
++    };
++  }
++
++  function getExpectedFromArgs(arg1, arg2, matchersUtil) {
++    var error, message;
++
++    if (isErrorConstructor(arg1)) {
++      error = arg1;
++      message = arg2;
++    } else {
++      error = Error;
++      message = arg1;
++    }
++
++    return {
++      error: error,
++      message: message,
++      printValue:
++        j$.fnNameFor(error) +
++        (typeof message === 'undefined' ? '' : ': ' + matchersUtil.pp(message))
++    };
++  }
++
++  function isErrorConstructor(value) {
++    return (
++      typeof value === 'function' &&
++      (value === Error || j$.isError_(value.prototype))
++    );
++  }
++};
++
++getJasmineRequireObj().toBeResolved = function(j$) {
++  /**
++   * Expect a promise to be resolved.
++   * @function
++   * @async
++   * @name async-matchers#toBeResolved
++   * @since 3.1.0
++   * @example
++   * await expectAsync(aPromise).toBeResolved();
++   * @example
++   * return expectAsync(aPromise).toBeResolved();
++   */
++  return function toBeResolved(matchersUtil) {
++    return {
++      compare: function(actual) {
++        if (!j$.isPromiseLike(actual)) {
++          throw new Error('Expected toBeResolved to be called on a promise.');
++        }
++
++        return actual.then(
++          function() {
++            return { pass: true };
++          },
++          function(e) {
++            return {
++              pass: false,
++              message:
++                'Expected a promise to be resolved but it was ' +
++                'rejected with ' +
++                matchersUtil.pp(e) +
++                '.'
++            };
++          }
++        );
++      }
++    };
++  };
++};
++
++getJasmineRequireObj().toBeResolvedTo = function(j$) {
++  /**
++   * Expect a promise to be resolved to a value equal to the expected, using deep equality comparison.
++   * @function
++   * @async
++   * @name async-matchers#toBeResolvedTo
++   * @since 3.1.0
++   * @param {Object} expected - Value that the promise is expected to resolve to
++   * @example
++   * await expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
++   * @example
++   * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
++   */
++  return function toBeResolvedTo(matchersUtil) {
++    return {
++      compare: function(actualPromise, expectedValue) {
++        if (!j$.isPromiseLike(actualPromise)) {
++          throw new Error('Expected toBeResolvedTo to be called on a promise.');
++        }
++
++        function prefix(passed) {
++          return (
++            'Expected a promise ' +
++            (passed ? 'not ' : '') +
++            'to be resolved to ' +
++            matchersUtil.pp(expectedValue)
++          );
++        }
++
++        return actualPromise.then(
++          function(actualValue) {
++            if (matchersUtil.equals(actualValue, expectedValue)) {
++              return {
++                pass: true,
++                message: prefix(true) + '.'
++              };
++            } else {
++              return {
++                pass: false,
++                message:
++                  prefix(false) +
++                  ' but it was resolved to ' +
++                  matchersUtil.pp(actualValue) +
++                  '.'
++              };
++            }
++          },
++          function(e) {
++            return {
++              pass: false,
++              message:
++                prefix(false) +
++                ' but it was rejected with ' +
++                matchersUtil.pp(e) +
++                '.'
++            };
++          }
++        );
++      }
++    };
++  };
++};
++
++getJasmineRequireObj().DiffBuilder = function(j$) {
++  return function DiffBuilder(config) {
++    var prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter(),
++      mismatches = new j$.MismatchTree(),
++      path = new j$.ObjectPath(),
++      actualRoot = undefined,
++      expectedRoot = undefined;
++
++    return {
++      setRoots: function(actual, expected) {
++        actualRoot = actual;
++        expectedRoot = expected;
++      },
++
++      recordMismatch: function(formatter) {
++        mismatches.add(path, formatter);
++      },
++
++      getMessage: function() {
++        var messages = [];
++
++        mismatches.traverse(function(path, isLeaf, formatter) {
++          var actualCustom,
++            expectedCustom,
++            useCustom,
++            derefResult = dereferencePath(
++              path,
++              actualRoot,
++              expectedRoot,
++              prettyPrinter
++            ),
++            actual = derefResult.actual,
++            expected = derefResult.expected;
++
++          if (formatter) {
++            messages.push(formatter(actual, expected, path, prettyPrinter));
++            return true;
++          }
++
++          actualCustom = prettyPrinter.customFormat_(actual);
++          expectedCustom = prettyPrinter.customFormat_(expected);
++          useCustom = !(
++            j$.util.isUndefined(actualCustom) &&
++            j$.util.isUndefined(expectedCustom)
++          );
++
++          if (useCustom) {
++            messages.push(
++              wrapPrettyPrinted(actualCustom, expectedCustom, path)
++            );
++            return false; // don't recurse further
++          }
++
++          if (isLeaf) {
++            messages.push(
++              defaultFormatter(actual, expected, path, prettyPrinter)
++            );
++          }
++
++          return true;
++        });
++
++        return messages.join('\n');
++      },
++
++      withPath: function(pathComponent, block) {
++        var oldPath = path;
++        path = path.add(pathComponent);
++        block();
++        path = oldPath;
++      }
++    };
++
++    function defaultFormatter(actual, expected, path, prettyPrinter) {
++      return wrapPrettyPrinted(
++        prettyPrinter(actual),
++        prettyPrinter(expected),
++        path
++      );
++    }
++
++    function wrapPrettyPrinted(actual, expected, path) {
++      return (
++        'Expected ' +
++        path +
++        (path.depth() ? ' = ' : '') +
++        actual +
++        ' to equal ' +
++        expected +
++        '.'
++      );
++    }
++  };
++
++  function dereferencePath(objectPath, actual, expected, pp) {
++    function handleAsymmetricExpected() {
++      if (
++        j$.isAsymmetricEqualityTester_(expected) &&
++        j$.isFunction_(expected.valuesForDiff_)
++      ) {
++        var asymmetricResult = expected.valuesForDiff_(actual, pp);
++        expected = asymmetricResult.self;
++        actual = asymmetricResult.other;
++      }
++    }
++
++    var i;
++    handleAsymmetricExpected();
++
++    for (i = 0; i < objectPath.components.length; i++) {
++      actual = actual[objectPath.components[i]];
++      expected = expected[objectPath.components[i]];
++      handleAsymmetricExpected();
++    }
++
++    return { actual: actual, expected: expected };
++  }
++};
++
++getJasmineRequireObj().MatchersUtil = function(j$) {
++  // TODO: convert all uses of j$.pp to use the injected pp
++
++  /**
++   * @class MatchersUtil
++   * @classdesc Utilities for use in implementing matchers.<br>
++   * _Note:_ Do not construct this directly. Jasmine will construct one and
++   * pass it to matchers and asymmetric equality testers.
++   * @hideconstructor
++   */
++  function MatchersUtil(options) {
++    options = options || {};
++    this.customTesters_ = options.customTesters || [];
++    /**
++     * Formats a value for use in matcher failure messages and similar contexts,
++     * taking into account the current set of custom value formatters.
++     * @function
++     * @name MatchersUtil#pp
++     * @since 3.6.0
++     * @param {*} value The value to pretty-print
++     * @return {string} The pretty-printed value
++     */
++    this.pp = options.pp || function() {};
++  }
++
++  /**
++   * Determines whether `haystack` contains `needle`, using the same comparison
++   * logic as {@link MatchersUtil#equals}.
++   * @function
++   * @name MatchersUtil#contains
++   * @since 2.0.0
++   * @param {*} haystack The collection to search
++   * @param {*} needle The value to search for
++   * @param [customTesters] An array of custom equality testers
++   * @returns {boolean} True if `needle` was found in `haystack`
++   */
++  MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
++    if (j$.isSet(haystack)) {
++      return haystack.has(needle);
++    }
++
++    if (
++      Object.prototype.toString.apply(haystack) === '[object Array]' ||
++      (!!haystack && !haystack.indexOf)
++    ) {
++      for (var i = 0; i < haystack.length; i++) {
++        if (this.equals(haystack[i], needle, customTesters)) {
++          return true;
++        }
++      }
++      return false;
++    }
++
++    return !!haystack && haystack.indexOf(needle) >= 0;
++  };
++
++  MatchersUtil.prototype.buildFailureMessage = function() {
++    var self = this;
++    var args = Array.prototype.slice.call(arguments, 0),
++      matcherName = args[0],
++      isNot = args[1],
++      actual = args[2],
++      expected = args.slice(3),
++      englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) {
++        return ' ' + s.toLowerCase();
++      });
++
++    var message =
++      'Expected ' +
++      self.pp(actual) +
++      (isNot ? ' not ' : ' ') +
++      englishyPredicate;
++
++    if (expected.length > 0) {
++      for (var i = 0; i < expected.length; i++) {
++        if (i > 0) {
++          message += ',';
++        }
++        message += ' ' + self.pp(expected[i]);
++      }
++    }
++
++    return message + '.';
++  };
++
++  MatchersUtil.prototype.asymmetricDiff_ = function(
++    a,
++    b,
++    aStack,
++    bStack,
++    customTesters,
++    diffBuilder
++  ) {
++    if (j$.isFunction_(b.valuesForDiff_)) {
++      var values = b.valuesForDiff_(a, this.pp);
++      this.eq_(
++        values.other,
++        values.self,
++        aStack,
++        bStack,
++        customTesters,
++        diffBuilder
++      );
++    } else {
++      diffBuilder.recordMismatch();
++    }
++  };
++
++  MatchersUtil.prototype.asymmetricMatch_ = function(
++    a,
++    b,
++    aStack,
++    bStack,
++    customTesters,
++    diffBuilder
++  ) {
++    var asymmetricA = j$.isAsymmetricEqualityTester_(a),
++      asymmetricB = j$.isAsymmetricEqualityTester_(b),
++      shim,
++      result;
++
++    if (asymmetricA === asymmetricB) {
++      return undefined;
++    }
++
++    shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters);
++
++    if (asymmetricA) {
++      result = a.asymmetricMatch(b, shim);
++      if (!result) {
++        diffBuilder.recordMismatch();
++      }
++      return result;
++    }
++
++    if (asymmetricB) {
++      result = b.asymmetricMatch(a, shim);
++      if (!result) {
++        this.asymmetricDiff_(a, b, aStack, bStack, customTesters, diffBuilder);
++      }
++      return result;
++    }
++  };
++
++  /**
++   * Determines whether two values are deeply equal to each other.
++   * @function
++   * @name MatchersUtil#equals
++   * @since 2.0.0
++   * @param {*} a The first value to compare
++   * @param {*} b The second value to compare
++   * @param [customTesters] An array of custom equality testers
++   * @returns {boolean} True if the values are equal
++   */
++  MatchersUtil.prototype.equals = function(
++    a,
++    b,
++    customTestersOrDiffBuilder,
++    diffBuilderOrNothing
++  ) {
++    var customTesters, diffBuilder;
++
++    if (isDiffBuilder(customTestersOrDiffBuilder)) {
++      diffBuilder = customTestersOrDiffBuilder;
++    } else {
++      customTesters = customTestersOrDiffBuilder;
++      diffBuilder = diffBuilderOrNothing;
++    }
++
++    customTesters = customTesters || this.customTesters_;
++    diffBuilder = diffBuilder || j$.NullDiffBuilder();
++    diffBuilder.setRoots(a, b);
++
++    return this.eq_(a, b, [], [], customTesters, diffBuilder);
++  };
++
++  // Equality function lovingly adapted from isEqual in
++  //   [Underscore](http://underscorejs.org)
++  MatchersUtil.prototype.eq_ = function(
++    a,
++    b,
++    aStack,
++    bStack,
++    customTesters,
++    diffBuilder
++  ) {
++    var result = true,
++      self = this,
++      i;
++
++    var asymmetricResult = this.asymmetricMatch_(
++      a,
++      b,
++      aStack,
++      bStack,
++      customTesters,
++      diffBuilder
++    );
++    if (!j$.util.isUndefined(asymmetricResult)) {
++      return asymmetricResult;
++    }
++
++    for (i = 0; i < customTesters.length; i++) {
++      var customTesterResult = customTesters[i](a, b);
++      if (!j$.util.isUndefined(customTesterResult)) {
++        if (!customTesterResult) {
++          diffBuilder.recordMismatch();
++        }
++        return customTesterResult;
++      }
++    }
++
++    if (a instanceof Error && b instanceof Error) {
++      result = a.message == b.message;
++      if (!result) {
++        diffBuilder.recordMismatch();
++      }
++      return result;
++    }
++
++    // Identical objects are equal. `0 === -0`, but they aren't identical.
++    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
++    if (a === b) {
++      result = a !== 0 || 1 / a == 1 / b;
++      if (!result) {
++        diffBuilder.recordMismatch();
++      }
++      return result;
++    }
++    // A strict comparison is necessary because `null == undefined`.
++    if (a === null || b === null) {
++      result = a === b;
++      if (!result) {
++        diffBuilder.recordMismatch();
++      }
++      return result;
++    }
++    var className = Object.prototype.toString.call(a);
++    if (className != Object.prototype.toString.call(b)) {
++      diffBuilder.recordMismatch();
++      return false;
++    }
++    switch (className) {
++      // Strings, numbers, dates, and booleans are compared by value.
++      case '[object String]':
++        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
++        // equivalent to `new String("5")`.
++        result = a == String(b);
++        if (!result) {
++          diffBuilder.recordMismatch();
++        }
++        return result;
++      case '[object Number]':
++        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
++        // other numeric values.
++        result =
++          a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b;
++        if (!result) {
++          diffBuilder.recordMismatch();
++        }
++        return result;
++      case '[object Date]':
++      case '[object Boolean]':
++        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
++        // millisecond representations. Note that invalid dates with millisecond representations
++        // of `NaN` are not equivalent.
++        result = +a == +b;
++        if (!result) {
++          diffBuilder.recordMismatch();
++        }
++        return result;
++      case '[object ArrayBuffer]':
++        // If we have an instance of ArrayBuffer the Uint8Array ctor
++        // will be defined as well
++        return self.eq_(
++          new Uint8Array(a), // eslint-disable-line compat/compat
++          new Uint8Array(b), // eslint-disable-line compat/compat
++          aStack,
++          bStack,
++          customTesters,
++          diffBuilder
++        );
++      // RegExps are compared by their source patterns and flags.
++      case '[object RegExp]':
++        return (
++          a.source == b.source &&
++          a.global == b.global &&
++          a.multiline == b.multiline &&
++          a.ignoreCase == b.ignoreCase
++        );
++    }
++    if (typeof a != 'object' || typeof b != 'object') {
++      diffBuilder.recordMismatch();
++      return false;
++    }
++
++    var aIsDomNode = j$.isDomNode(a);
++    var bIsDomNode = j$.isDomNode(b);
++    if (aIsDomNode && bIsDomNode) {
++      // At first try to use DOM3 method isEqualNode
++      result = a.isEqualNode(b);
++      if (!result) {
++        diffBuilder.recordMismatch();
++      }
++      return result;
++    }
++    if (aIsDomNode || bIsDomNode) {
++      diffBuilder.recordMismatch();
++      return false;
++    }
++
++    var aIsPromise = j$.isPromise(a);
++    var bIsPromise = j$.isPromise(b);
++    if (aIsPromise && bIsPromise) {
++      return a === b;
++    }
++
++    // Assume equality for cyclic structures. The algorithm for detecting cyclic
++    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
++    var length = aStack.length;
++    while (length--) {
++      // Linear search. Performance is inversely proportional to the number of
++      // unique nested structures.
++      if (aStack[length] == a) {
++        return bStack[length] == b;
++      }
++    }
++    // Add the first object to the stack of traversed objects.
++    aStack.push(a);
++    bStack.push(b);
++    var size = 0;
++    // Recursively compare objects and arrays.
++    // Compare array lengths to determine if a deep comparison is necessary.
++    if (className == '[object Array]') {
++      var aLength = a.length;
++      var bLength = b.length;
++
++      diffBuilder.withPath('length', function() {
++        if (aLength !== bLength) {
++          diffBuilder.recordMismatch();
++          result = false;
++        }
++      });
++
++      for (i = 0; i < aLength || i < bLength; i++) {
++        diffBuilder.withPath(i, function() {
++          if (i >= bLength) {
++            diffBuilder.recordMismatch(
++              actualArrayIsLongerFormatter.bind(null, self.pp)
++            );
++            result = false;
++          } else {
++            result =
++              self.eq_(
++                i < aLength ? a[i] : void 0,
++                i < bLength ? b[i] : void 0,
++                aStack,
++                bStack,
++                customTesters,
++                diffBuilder
++              ) && result;
++          }
++        });
++      }
++      if (!result) {
++        return false;
++      }
++    } else if (j$.isMap(a) && j$.isMap(b)) {
++      if (a.size != b.size) {
++        diffBuilder.recordMismatch();
++        return false;
++      }
++
++      var keysA = [];
++      var keysB = [];
++      a.forEach(function(valueA, keyA) {
++        keysA.push(keyA);
++      });
++      b.forEach(function(valueB, keyB) {
++        keysB.push(keyB);
++      });
++
++      // For both sets of keys, check they map to equal values in both maps.
++      // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys.
++      var mapKeys = [keysA, keysB];
++      var cmpKeys = [keysB, keysA];
++      var mapIter, mapKey, mapValueA, mapValueB;
++      var cmpIter, cmpKey;
++      for (i = 0; result && i < mapKeys.length; i++) {
++        mapIter = mapKeys[i];
++        cmpIter = cmpKeys[i];
++
++        for (var j = 0; result && j < mapIter.length; j++) {
++          mapKey = mapIter[j];
++          cmpKey = cmpIter[j];
++          mapValueA = a.get(mapKey);
++
++          // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
++          // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
++          // obj identity (that are otherwise equal) to not match.
++          if (
++            j$.isAsymmetricEqualityTester_(mapKey) ||
++            (j$.isAsymmetricEqualityTester_(cmpKey) &&
++              this.eq_(
++                mapKey,
++                cmpKey,
++                aStack,
++                bStack,
++                customTesters,
++                j$.NullDiffBuilder()
++              ))
++          ) {
++            mapValueB = b.get(cmpKey);
++          } else {
++            mapValueB = b.get(mapKey);
++          }
++          result = this.eq_(
++            mapValueA,
++            mapValueB,
++            aStack,
++            bStack,
++            customTesters,
++            j$.NullDiffBuilder()
++          );
++        }
++      }
++
++      if (!result) {
++        diffBuilder.recordMismatch();
++        return false;
++      }
++    } else if (j$.isSet(a) && j$.isSet(b)) {
++      if (a.size != b.size) {
++        diffBuilder.recordMismatch();
++        return false;
++      }
++
++      var valuesA = [];
++      a.forEach(function(valueA) {
++        valuesA.push(valueA);
++      });
++      var valuesB = [];
++      b.forEach(function(valueB) {
++        valuesB.push(valueB);
++      });
++
++      // For both sets, check they are all contained in the other set
++      var setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
++      var stackPairs = [[aStack, bStack], [bStack, aStack]];
++      var baseValues, baseValue, baseStack;
++      var otherValues, otherValue, otherStack;
++      var found;
++      var prevStackSize;
++      for (i = 0; result && i < setPairs.length; i++) {
++        baseValues = setPairs[i][0];
++        otherValues = setPairs[i][1];
++        baseStack = stackPairs[i][0];
++        otherStack = stackPairs[i][1];
++        // For each value in the base set...
++        for (var k = 0; result && k < baseValues.length; k++) {
++          baseValue = baseValues[k];
++          found = false;
++          // ... test that it is present in the other set
++          for (var l = 0; !found && l < otherValues.length; l++) {
++            otherValue = otherValues[l];
++            prevStackSize = baseStack.length;
++            // compare by value equality
++            found = this.eq_(
++              baseValue,
++              otherValue,
++              baseStack,
++              otherStack,
++              customTesters,
++              j$.NullDiffBuilder()
++            );
++            if (!found && prevStackSize !== baseStack.length) {
++              baseStack.splice(prevStackSize);
++              otherStack.splice(prevStackSize);
++            }
++          }
++          result = result && found;
++        }
++      }
++
++      if (!result) {
++        diffBuilder.recordMismatch();
++        return false;
++      }
++    } else if (j$.isURL(a) && j$.isURL(b)) {
++      // URLs have no enumrable properties, so the default object comparison
++      // would consider any two URLs to be equal.
++      return a.toString() === b.toString();
++    } else {
++      // Objects with different constructors are not equivalent, but `Object`s
++      // or `Array`s from different frames are.
++      var aCtor = a.constructor,
++        bCtor = b.constructor;
++      if (
++        aCtor !== bCtor &&
++        isFunction(aCtor) &&
++        isFunction(bCtor) &&
++        a instanceof aCtor &&
++        b instanceof bCtor &&
++        !(aCtor instanceof aCtor && bCtor instanceof bCtor)
++      ) {
++        diffBuilder.recordMismatch(
++          constructorsAreDifferentFormatter.bind(null, this.pp)
++        );
++        return false;
++      }
++    }
++
++    // Deep compare objects.
++    var aKeys = keys(a, className == '[object Array]'),
++      key;
++    size = aKeys.length;
++
++    // Ensure that both objects contain the same number of properties before comparing deep equality.
++    if (keys(b, className == '[object Array]').length !== size) {
++      diffBuilder.recordMismatch(
++        objectKeysAreDifferentFormatter.bind(null, this.pp)
++      );
++      return false;
++    }
++
++    for (i = 0; i < size; i++) {
++      key = aKeys[i];
++      // Deep compare each member
++      if (!j$.util.has(b, key)) {
++        diffBuilder.recordMismatch(
++          objectKeysAreDifferentFormatter.bind(null, this.pp)
++        );
++        result = false;
++        continue;
++      }
++
++      diffBuilder.withPath(key, function() {
++        if (
++          !self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder)
++        ) {
++          result = false;
++        }
++      });
++    }
++
++    if (!result) {
++      return false;
++    }
++
++    // Remove the first object from the stack of traversed objects.
++    aStack.pop();
++    bStack.pop();
++
++    return result;
++  };
++
++  function keys(obj, isArray) {
++    var allKeys = Object.keys
++      ? Object.keys(obj)
++      : (function(o) {
++          var keys = [];
++          for (var key in o) {
++            if (j$.util.has(o, key)) {
++              keys.push(key);
++            }
++          }
++          return keys;
++        })(obj);
++
++    if (!isArray) {
++      return allKeys;
++    }
++
++    if (allKeys.length === 0) {
++      return allKeys;
++    }
++
++    var extraKeys = [];
++    for (var i = 0; i < allKeys.length; i++) {
++      if (!/^[0-9]+$/.test(allKeys[i])) {
++        extraKeys.push(allKeys[i]);
++      }
++    }
++
++    return extraKeys;
++  }
++
++  function isFunction(obj) {
++    return typeof obj === 'function';
++  }
++
++  function objectKeysAreDifferentFormatter(pp, actual, expected, path) {
++    var missingProperties = j$.util.objectDifference(expected, actual),
++      extraProperties = j$.util.objectDifference(actual, expected),
++      missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties),
++      extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties),
++      messages = [];
++
++    if (!path.depth()) {
++      path = 'object';
++    }
++
++    if (missingPropertiesMessage.length) {
++      messages.push(
++        'Expected ' + path + ' to have properties' + missingPropertiesMessage
++      );
++    }
++
++    if (extraPropertiesMessage.length) {
++      messages.push(
++        'Expected ' + path + ' not to have properties' + extraPropertiesMessage
++      );
++    }
++
++    return messages.join('\n');
++  }
++
++  function constructorsAreDifferentFormatter(pp, actual, expected, path) {
++    if (!path.depth()) {
++      path = 'object';
++    }
++
++    return (
++      'Expected ' +
++      path +
++      ' to be a kind of ' +
++      j$.fnNameFor(expected.constructor) +
++      ', but was ' +
++      pp(actual) +
++      '.'
++    );
++  }
++
++  function actualArrayIsLongerFormatter(pp, actual, expected, path) {
++    return (
++      'Unexpected ' +
++      path +
++      (path.depth() ? ' = ' : '') +
++      pp(actual) +
++      ' in array.'
++    );
++  }
++
++  function formatKeyValuePairs(pp, obj) {
++    var formatted = '';
++    for (var key in obj) {
++      formatted += '\n    ' + key + ': ' + pp(obj[key]);
++    }
++    return formatted;
++  }
++
++  function isDiffBuilder(obj) {
++    return obj && typeof obj.recordMismatch === 'function';
++  }
++
++  return MatchersUtil;
++};
++
++/**
++ * @interface AsymmetricEqualityTester
++ * @classdesc An asymmetric equality tester is an object that can match multiple
++ * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine
++ * includes a number of built-in asymmetric equality testers, such as
++ * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are
++ * also supported.
++ *
++ * Asymmetric equality testers work with any matcher, including user-defined
++ * custom matchers, that uses {@link MatchersUtil#equals} or
++ * {@link MatchersUtil#contains}.
++ *
++ * @example
++ * function numberDivisibleBy(divisor) {
++ *   return {
++ *     asymmetricMatch: function(n) {
++ *       return typeof n === 'number' && n % divisor === 0;
++ *     },
++ *     jasmineToString: function() {
++ *       return `<a number divisible by ${divisor}>`;
++ *     }
++ *   };
++ * }
++ *
++ * var actual = {
++ *   n: 2,
++ *   otherFields: "don't care"
++ * };
++ *
++ * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)}));
++ * @see custom_asymmetric_equality_testers
++ * @since 2.0.0
++ */
++/**
++ * Determines whether a value matches this tester
++ * @function
++ * @name AsymmetricEqualityTester#asymmetricMatch
++ * @param value {any} The value to test
++ * @param matchersUtil {MatchersUtil} utilities for testing equality, etc
++ * @return {Boolean}
++ */
++/**
++ * Returns a string representation of this tester to use in matcher failure messages
++ * @function
++ * @name AsymmetricEqualityTester#jasmineToString
++ * @param pp {function} Function that takes a value and returns a pretty-printed representation
++ * @return {String}
++ */
++
++getJasmineRequireObj().MismatchTree = function(j$) {
++  /*
++    To be able to apply custom object formatters at all possible levels of an
++    object graph, DiffBuilder needs to be able to know not just where the
++    mismatch occurred but also all ancestors of the mismatched value in both
++    the expected and actual object graphs. MismatchTree maintains that context
++    and provides it via the traverse method.
++   */
++  function MismatchTree(path) {
++    this.path = path || new j$.ObjectPath([]);
++    this.formatter = undefined;
++    this.children = [];
++    this.isMismatch = false;
++  }
++
++  MismatchTree.prototype.add = function(path, formatter) {
++    var key, child;
++
++    if (path.depth() === 0) {
++      this.formatter = formatter;
++      this.isMismatch = true;
++    } else {
++      key = path.components[0];
++      path = path.shift();
++      child = this.child(key);
++
++      if (!child) {
++        child = new MismatchTree(this.path.add(key));
++        this.children.push(child);
++      }
++
++      child.add(path, formatter);
++    }
++  };
++
++  MismatchTree.prototype.traverse = function(visit) {
++    var i,
++      hasChildren = this.children.length > 0;
++
++    if (this.isMismatch || hasChildren) {
++      if (visit(this.path, !hasChildren, this.formatter)) {
++        for (i = 0; i < this.children.length; i++) {
++          this.children[i].traverse(visit);
++        }
++      }
++    }
++  };
++
++  MismatchTree.prototype.child = function(key) {
++    var i, pathEls;
++
++    for (i = 0; i < this.children.length; i++) {
++      pathEls = this.children[i].path.components;
++      if (pathEls[pathEls.length - 1] === key) {
++        return this.children[i];
++      }
++    }
++  };
++
++  return MismatchTree;
++};
++
++getJasmineRequireObj().nothing = function() {
++  /**
++   * {@link expect} nothing explicitly.
++   * @function
++   * @name matchers#nothing
++   * @since 2.8.0
++   * @example
++   * expect().nothing();
++   */
++  function nothing() {
++    return {
++      compare: function() {
++        return {
++          pass: true
++        };
++      }
++    };
++  }
++
++  return nothing;
++};
++
++getJasmineRequireObj().NullDiffBuilder = function(j$) {
++  return function() {
++    return {
++      withPath: function(_, block) {
++        block();
++      },
++      setRoots: function() {},
++      recordMismatch: function() {}
++    };
++  };
++};
++
++getJasmineRequireObj().ObjectPath = function(j$) {
++  function ObjectPath(components) {
++    this.components = components || [];
++  }
++
++  ObjectPath.prototype.toString = function() {
++    if (this.components.length) {
++      return '$' + map(this.components, formatPropertyAccess).join('');
++    } else {
++      return '';
++    }
++  };
++
++  ObjectPath.prototype.add = function(component) {
++    return new ObjectPath(this.components.concat([component]));
++  };
++
++  ObjectPath.prototype.shift = function() {
++    return new ObjectPath(this.components.slice(1));
++  };
++
++  ObjectPath.prototype.depth = function() {
++    return this.components.length;
++  };
++
++  function formatPropertyAccess(prop) {
++    if (typeof prop === 'number') {
++      return '[' + prop + ']';
++    }
++
++    if (isValidIdentifier(prop)) {
++      return '.' + prop;
++    }
++
++    return "['" + prop + "']";
++  }
++
++  function map(array, fn) {
++    var results = [];
++    for (var i = 0; i < array.length; i++) {
++      results.push(fn(array[i]));
++    }
++    return results;
++  }
++
++  function isValidIdentifier(string) {
++    return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string);
++  }
++
++  return ObjectPath;
++};
++
++getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) {
++  var availableMatchers = [
++      'toBePending',
++      'toBeResolved',
++      'toBeRejected',
++      'toBeResolvedTo',
++      'toBeRejectedWith',
++      'toBeRejectedWithError'
++    ],
++    matchers = {};
++
++  for (var i = 0; i < availableMatchers.length; i++) {
++    var name = availableMatchers[i];
++    matchers[name] = jRequire[name](j$);
++  }
++
++  return matchers;
++};
++
++getJasmineRequireObj().toBe = function(j$) {
++  /**
++   * {@link expect} the actual value to be `===` to the expected value.
++   * @function
++   * @name matchers#toBe
++   * @since 1.3.0
++   * @param {Object} expected - The expected value to compare against.
++   * @example
++   * expect(thing).toBe(realThing);
++   */
++  function toBe(matchersUtil) {
++    var tip =
++      ' Tip: To check for deep equality, use .toEqual() instead of .toBe().';
++
++    return {
++      compare: function(actual, expected) {
++        var result = {
++          pass: actual === expected
++        };
++
++        if (typeof expected === 'object') {
++          result.message =
++            matchersUtil.buildFailureMessage(
++              'toBe',
++              result.pass,
++              actual,
++              expected
++            ) + tip;
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toBe;
++};
++
++getJasmineRequireObj().toBeCloseTo = function() {
++  /**
++   * {@link expect} the actual value to be within a specified precision of the expected value.
++   * @function
++   * @name matchers#toBeCloseTo
++   * @since 1.3.0
++   * @param {Object} expected - The expected value to compare against.
++   * @param {Number} [precision=2] - The number of decimal points to check.
++   * @example
++   * expect(number).toBeCloseTo(42.2, 3);
++   */
++  function toBeCloseTo() {
++    return {
++      compare: function(actual, expected, precision) {
++        if (precision !== 0) {
++          precision = precision || 2;
++        }
++
++        if (expected === null || actual === null) {
++          throw new Error(
++            'Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
++              'expect(' +
++              actual +
++              ').toBeCloseTo(' +
++              expected +
++              ').'
++          );
++        }
++
++        var pow = Math.pow(10, precision + 1);
++        var delta = Math.abs(expected - actual);
++        var maxDelta = Math.pow(10, -precision) / 2;
++
++        return {
++          pass: Math.round(delta * pow) <= maxDelta * pow
++        };
++      }
++    };
++  }
++
++  return toBeCloseTo;
++};
++
++getJasmineRequireObj().toBeDefined = function() {
++  /**
++   * {@link expect} the actual value to be defined. (Not `undefined`)
++   * @function
++   * @name matchers#toBeDefined
++   * @since 1.3.0
++   * @example
++   * expect(result).toBeDefined();
++   */
++  function toBeDefined() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: void 0 !== actual
++        };
++      }
++    };
++  }
++
++  return toBeDefined;
++};
++
++getJasmineRequireObj().toBeFalse = function() {
++  /**
++   * {@link expect} the actual value to be `false`.
++   * @function
++   * @name matchers#toBeFalse
++   * @since 3.5.0
++   * @example
++   * expect(result).toBeFalse();
++   */
++  function toBeFalse() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: actual === false
++        };
++      }
++    };
++  }
++
++  return toBeFalse;
++};
++
++getJasmineRequireObj().toBeFalsy = function() {
++  /**
++   * {@link expect} the actual value to be falsy
++   * @function
++   * @name matchers#toBeFalsy
++   * @since 2.0.0
++   * @example
++   * expect(result).toBeFalsy();
++   */
++  function toBeFalsy() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: !actual
++        };
++      }
++    };
++  }
++
++  return toBeFalsy;
++};
++
++getJasmineRequireObj().toBeGreaterThan = function() {
++  /**
++   * {@link expect} the actual value to be greater than the expected value.
++   * @function
++   * @name matchers#toBeGreaterThan
++   * @since 2.0.0
++   * @param {Number} expected - The value to compare against.
++   * @example
++   * expect(result).toBeGreaterThan(3);
++   */
++  function toBeGreaterThan() {
++    return {
++      compare: function(actual, expected) {
++        return {
++          pass: actual > expected
++        };
++      }
++    };
++  }
++
++  return toBeGreaterThan;
++};
++
++getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
++  /**
++   * {@link expect} the actual value to be greater than or equal to the expected value.
++   * @function
++   * @name matchers#toBeGreaterThanOrEqual
++   * @since 2.0.0
++   * @param {Number} expected - The expected value to compare against.
++   * @example
++   * expect(result).toBeGreaterThanOrEqual(25);
++   */
++  function toBeGreaterThanOrEqual() {
++    return {
++      compare: function(actual, expected) {
++        return {
++          pass: actual >= expected
++        };
++      }
++    };
++  }
++
++  return toBeGreaterThanOrEqual;
++};
++
++getJasmineRequireObj().toBeInstanceOf = function(j$) {
++  var usageError = j$.formatErrorMsg(
++    '<toBeInstanceOf>',
++    'expect(value).toBeInstanceOf(<ConstructorFunction>)'
++  );
++
++  /**
++   * {@link expect} the actual to be an instance of the expected class
++   * @function
++   * @name matchers#toBeInstanceOf
++   * @since 3.5.0
++   * @param {Object} expected - The class or constructor function to check for
++   * @example
++   * expect('foo').toBeInstanceOf(String);
++   * expect(3).toBeInstanceOf(Number);
++   * expect(new Error()).toBeInstanceOf(Error);
++   */
++  function toBeInstanceOf(matchersUtil) {
++    return {
++      compare: function(actual, expected) {
++        var actualType =
++            actual && actual.constructor
++              ? j$.fnNameFor(actual.constructor)
++              : matchersUtil.pp(actual),
++          expectedType = expected
++            ? j$.fnNameFor(expected)
++            : matchersUtil.pp(expected),
++          expectedMatcher,
++          pass;
++
++        try {
++          expectedMatcher = new j$.Any(expected);
++          pass = expectedMatcher.asymmetricMatch(actual);
++        } catch (error) {
++          throw new Error(
++            usageError('Expected value is not a constructor function')
++          );
++        }
++
++        if (pass) {
++          return {
++            pass: true,
++            message:
++              'Expected instance of ' +
++              actualType +
++              ' not to be an instance of ' +
++              expectedType
++          };
++        } else {
++          return {
++            pass: false,
++            message:
++              'Expected instance of ' +
++              actualType +
++              ' to be an instance of ' +
++              expectedType
++          };
++        }
++      }
++    };
++  }
++
++  return toBeInstanceOf;
++};
++
++getJasmineRequireObj().toBeLessThan = function() {
++  /**
++   * {@link expect} the actual value to be less than the expected value.
++   * @function
++   * @name matchers#toBeLessThan
++   * @since 2.0.0
++   * @param {Number} expected - The expected value to compare against.
++   * @example
++   * expect(result).toBeLessThan(0);
++   */
++  function toBeLessThan() {
++    return {
++      compare: function(actual, expected) {
++        return {
++          pass: actual < expected
++        };
++      }
++    };
++  }
++
++  return toBeLessThan;
++};
++
++getJasmineRequireObj().toBeLessThanOrEqual = function() {
++  /**
++   * {@link expect} the actual value to be less than or equal to the expected value.
++   * @function
++   * @name matchers#toBeLessThanOrEqual
++   * @since 2.0.0
++   * @param {Number} expected - The expected value to compare against.
++   * @example
++   * expect(result).toBeLessThanOrEqual(123);
++   */
++  function toBeLessThanOrEqual() {
++    return {
++      compare: function(actual, expected) {
++        return {
++          pass: actual <= expected
++        };
++      }
++    };
++  }
++
++  return toBeLessThanOrEqual;
++};
++
++getJasmineRequireObj().toBeNaN = function(j$) {
++  /**
++   * {@link expect} the actual value to be `NaN` (Not a Number).
++   * @function
++   * @name matchers#toBeNaN
++   * @since 1.3.0
++   * @example
++   * expect(thing).toBeNaN();
++   */
++  function toBeNaN(matchersUtil) {
++    return {
++      compare: function(actual) {
++        var result = {
++          pass: actual !== actual
++        };
++
++        if (result.pass) {
++          result.message = 'Expected actual not to be NaN.';
++        } else {
++          result.message = function() {
++            return 'Expected ' + matchersUtil.pp(actual) + ' to be NaN.';
++          };
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toBeNaN;
++};
++
++getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
++  /**
++   * {@link expect} the actual value to be `-Infinity` (-infinity).
++   * @function
++   * @name matchers#toBeNegativeInfinity
++   * @since 2.6.0
++   * @example
++   * expect(thing).toBeNegativeInfinity();
++   */
++  function toBeNegativeInfinity(matchersUtil) {
++    return {
++      compare: function(actual) {
++        var result = {
++          pass: actual === Number.NEGATIVE_INFINITY
++        };
++
++        if (result.pass) {
++          result.message = 'Expected actual not to be -Infinity.';
++        } else {
++          result.message = function() {
++            return 'Expected ' + matchersUtil.pp(actual) + ' to be -Infinity.';
++          };
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toBeNegativeInfinity;
++};
++
++getJasmineRequireObj().toBeNull = function() {
++  /**
++   * {@link expect} the actual value to be `null`.
++   * @function
++   * @name matchers#toBeNull
++   * @since 1.3.0
++   * @example
++   * expect(result).toBeNull();
++   */
++  function toBeNull() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: actual === null
++        };
++      }
++    };
++  }
++
++  return toBeNull;
++};
++
++getJasmineRequireObj().toBePositiveInfinity = function(j$) {
++  /**
++   * {@link expect} the actual value to be `Infinity` (infinity).
++   * @function
++   * @name matchers#toBePositiveInfinity
++   * @since 2.6.0
++   * @example
++   * expect(thing).toBePositiveInfinity();
++   */
++  function toBePositiveInfinity(matchersUtil) {
++    return {
++      compare: function(actual) {
++        var result = {
++          pass: actual === Number.POSITIVE_INFINITY
++        };
++
++        if (result.pass) {
++          result.message = 'Expected actual not to be Infinity.';
++        } else {
++          result.message = function() {
++            return 'Expected ' + matchersUtil.pp(actual) + ' to be Infinity.';
++          };
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toBePositiveInfinity;
++};
++
++getJasmineRequireObj().toBeTrue = function() {
++  /**
++   * {@link expect} the actual value to be `true`.
++   * @function
++   * @name matchers#toBeTrue
++   * @since 3.5.0
++   * @example
++   * expect(result).toBeTrue();
++   */
++  function toBeTrue() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: actual === true
++        };
++      }
++    };
++  }
++
++  return toBeTrue;
++};
++
++getJasmineRequireObj().toBeTruthy = function() {
++  /**
++   * {@link expect} the actual value to be truthy.
++   * @function
++   * @name matchers#toBeTruthy
++   * @since 2.0.0
++   * @example
++   * expect(thing).toBeTruthy();
++   */
++  function toBeTruthy() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: !!actual
++        };
++      }
++    };
++  }
++
++  return toBeTruthy;
++};
++
++getJasmineRequireObj().toBeUndefined = function() {
++  /**
++   * {@link expect} the actual value to be `undefined`.
++   * @function
++   * @name matchers#toBeUndefined
++   * @since 1.3.0
++   * @example
++   * expect(result).toBeUndefined():
++   */
++  function toBeUndefined() {
++    return {
++      compare: function(actual) {
++        return {
++          pass: void 0 === actual
++        };
++      }
++    };
++  }
++
++  return toBeUndefined;
++};
++
++getJasmineRequireObj().toContain = function() {
++  /**
++   * {@link expect} the actual value to contain a specific value.
++   * @function
++   * @name matchers#toContain
++   * @since 2.0.0
++   * @param {Object} expected - The value to look for.
++   * @example
++   * expect(array).toContain(anElement);
++   * expect(string).toContain(substring);
++   */
++  function toContain(matchersUtil) {
++    return {
++      compare: function(actual, expected) {
++        return {
++          pass: matchersUtil.contains(actual, expected)
++        };
++      }
++    };
++  }
++
++  return toContain;
++};
++
++getJasmineRequireObj().toEqual = function(j$) {
++  /**
++   * {@link expect} the actual value to be equal to the expected, using deep equality comparison.
++   * @function
++   * @name matchers#toEqual
++   * @since 1.3.0
++   * @param {Object} expected - Expected value
++   * @example
++   * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
++   */
++  function toEqual(matchersUtil) {
++    return {
++      compare: function(actual, expected) {
++        var result = {
++            pass: false
++          },
++          diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp });
++
++        result.pass = matchersUtil.equals(actual, expected, diffBuilder);
++
++        // TODO: only set error message if test fails
++        result.message = diffBuilder.getMessage();
++
++        return result;
++      }
++    };
++  }
++
++  return toEqual;
++};
++
++getJasmineRequireObj().toHaveBeenCalled = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toHaveBeenCalled>',
++    'expect(<spyObj>).toHaveBeenCalled()'
++  );
++
++  /**
++   * {@link expect} the actual (a {@link Spy}) to have been called.
++   * @function
++   * @name matchers#toHaveBeenCalled
++   * @since 1.3.0
++   * @example
++   * expect(mySpy).toHaveBeenCalled();
++   * expect(mySpy).not.toHaveBeenCalled();
++   */
++  function toHaveBeenCalled(matchersUtil) {
++    return {
++      compare: function(actual) {
++        var result = {};
++
++        if (!j$.isSpy(actual)) {
++          throw new Error(
++            getErrorMsg(
++              'Expected a spy, but got ' + matchersUtil.pp(actual) + '.'
++            )
++          );
++        }
++
++        if (arguments.length > 1) {
++          throw new Error(
++            getErrorMsg('Does not take arguments, use toHaveBeenCalledWith')
++          );
++        }
++
++        result.pass = actual.calls.any();
++
++        result.message = result.pass
++          ? 'Expected spy ' + actual.and.identity + ' not to have been called.'
++          : 'Expected spy ' + actual.and.identity + ' to have been called.';
++
++        return result;
++      }
++    };
++  }
++
++  return toHaveBeenCalled;
++};
++
++getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toHaveBeenCalledBefore>',
++    'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)'
++  );
++
++  /**
++   * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
++   * @function
++   * @name matchers#toHaveBeenCalledBefore
++   * @since 2.6.0
++   * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
++   * @example
++   * expect(mySpy).toHaveBeenCalledBefore(otherSpy);
++   */
++  function toHaveBeenCalledBefore(matchersUtil) {
++    return {
++      compare: function(firstSpy, latterSpy) {
++        if (!j$.isSpy(firstSpy)) {
++          throw new Error(
++            getErrorMsg(
++              'Expected a spy, but got ' + matchersUtil.pp(firstSpy) + '.'
++            )
++          );
++        }
++        if (!j$.isSpy(latterSpy)) {
++          throw new Error(
++            getErrorMsg(
++              'Expected a spy, but got ' + matchersUtil.pp(latterSpy) + '.'
++            )
++          );
++        }
++
++        var result = { pass: false };
++
++        if (!firstSpy.calls.count()) {
++          result.message =
++            'Expected spy ' + firstSpy.and.identity + ' to have been called.';
++          return result;
++        }
++        if (!latterSpy.calls.count()) {
++          result.message =
++            'Expected spy ' + latterSpy.and.identity + ' to have been called.';
++          return result;
++        }
++
++        var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder;
++        var first2ndSpyCall = latterSpy.calls.first().invocationOrder;
++
++        result.pass = latest1stSpyCall < first2ndSpyCall;
++
++        if (result.pass) {
++          result.message =
++            'Expected spy ' +
++            firstSpy.and.identity +
++            ' to not have been called before spy ' +
++            latterSpy.and.identity +
++            ', but it was';
++        } else {
++          var first1stSpyCall = firstSpy.calls.first().invocationOrder;
++          var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
++
++          if (first1stSpyCall < first2ndSpyCall) {
++            result.message =
++              'Expected latest call to spy ' +
++              firstSpy.and.identity +
++              ' to have been called before first call to spy ' +
++              latterSpy.and.identity +
++              ' (no interleaved calls)';
++          } else if (latest2ndSpyCall > latest1stSpyCall) {
++            result.message =
++              'Expected first call to spy ' +
++              latterSpy.and.identity +
++              ' to have been called after latest call to spy ' +
++              firstSpy.and.identity +
++              ' (no interleaved calls)';
++          } else {
++            result.message =
++              'Expected spy ' +
++              firstSpy.and.identity +
++              ' to have been called before spy ' +
++              latterSpy.and.identity;
++          }
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toHaveBeenCalledBefore;
++};
++
++getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toHaveBeenCalledOnceWith>',
++    'expect(<spyObj>).toHaveBeenCalledOnceWith(...arguments)'
++  );
++
++  /**
++   * {@link expect} the actual (a {@link Spy}) to have been called exactly once, and exactly with the particular arguments.
++   * @function
++   * @name matchers#toHaveBeenCalledOnceWith
++   * @since 3.6.0
++   * @param {...Object} - The arguments to look for
++   * @example
++   * expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2);
++   */
++  function toHaveBeenCalledOnceWith(util) {
++    return {
++      compare: function() {
++        var args = Array.prototype.slice.call(arguments, 0),
++          actual = args[0],
++          expectedArgs = args.slice(1);
++
++        if (!j$.isSpy(actual)) {
++          throw new Error(
++            getErrorMsg('Expected a spy, but got ' + util.pp(actual) + '.')
++          );
++        }
++
++        var prettyPrintedCalls = actual.calls
++          .allArgs()
++          .map(function(argsForCall) {
++            return '  ' + util.pp(argsForCall);
++          });
++
++        if (
++          actual.calls.count() === 1 &&
++          util.contains(actual.calls.allArgs(), expectedArgs)
++        ) {
++          return {
++            pass: true,
++            message:
++              'Expected spy ' +
++              actual.and.identity +
++              ' to have been called 0 times, multiple times, or once, but with arguments different from:\n' +
++              '  ' +
++              util.pp(expectedArgs) +
++              '\n' +
++              'But the actual call was:\n' +
++              prettyPrintedCalls.join(',\n') +
++              '.\n\n'
++          };
++        }
++
++        function getDiffs() {
++          return actual.calls.allArgs().map(function(argsForCall, callIx) {
++            var diffBuilder = new j$.DiffBuilder();
++            util.equals(argsForCall, expectedArgs, diffBuilder);
++            return diffBuilder.getMessage();
++          });
++        }
++
++        function butString() {
++          switch (actual.calls.count()) {
++            case 0:
++              return 'But it was never called.\n\n';
++            case 1:
++              return (
++                'But the actual call was:\n' +
++                prettyPrintedCalls.join(',\n') +
++                '.\n' +
++                getDiffs().join('\n') +
++                '\n\n'
++              );
++            default:
++              return (
++                'But the actual calls were:\n' +
++                prettyPrintedCalls.join(',\n') +
++                '.\n\n'
++              );
++          }
++        }
++
++        return {
++          pass: false,
++          message:
++            'Expected spy ' +
++            actual.and.identity +
++            ' to have been called only once, and with given args:\n' +
++            '  ' +
++            util.pp(expectedArgs) +
++            '\n' +
++            butString()
++        };
++      }
++    };
++  }
++
++  return toHaveBeenCalledOnceWith;
++};
++
++getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toHaveBeenCalledTimes>',
++    'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)'
++  );
++
++  /**
++   * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
++   * @function
++   * @name matchers#toHaveBeenCalledTimes
++   * @since 2.4.0
++   * @param {Number} expected - The number of invocations to look for.
++   * @example
++   * expect(mySpy).toHaveBeenCalledTimes(3);
++   */
++  function toHaveBeenCalledTimes(matchersUtil) {
++    return {
++      compare: function(actual, expected) {
++        if (!j$.isSpy(actual)) {
++          throw new Error(
++            getErrorMsg(
++              'Expected a spy, but got ' + matchersUtil.pp(actual) + '.'
++            )
++          );
++        }
++
++        var args = Array.prototype.slice.call(arguments, 0),
++          result = { pass: false };
++
++        if (!j$.isNumber_(expected)) {
++          throw new Error(
++            getErrorMsg(
++              'The expected times failed is a required argument and must be a number.'
++            )
++          );
++        }
++
++        actual = args[0];
++        var calls = actual.calls.count();
++        var timesMessage = expected === 1 ? 'once' : expected + ' times';
++        result.pass = calls === expected;
++        result.message = result.pass
++          ? 'Expected spy ' +
++            actual.and.identity +
++            ' not to have been called ' +
++            timesMessage +
++            '. It was called ' +
++            calls +
++            ' times.'
++          : 'Expected spy ' +
++            actual.and.identity +
++            ' to have been called ' +
++            timesMessage +
++            '. It was called ' +
++            calls +
++            ' times.';
++        return result;
++      }
++    };
++  }
++
++  return toHaveBeenCalledTimes;
++};
++
++getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toHaveBeenCalledWith>',
++    'expect(<spyObj>).toHaveBeenCalledWith(...arguments)'
++  );
++
++  /**
++   * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
++   * @function
++   * @name matchers#toHaveBeenCalledWith
++   * @since 1.3.0
++   * @param {...Object} - The arguments to look for
++   * @example
++   * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
++   */
++  function toHaveBeenCalledWith(matchersUtil) {
++    return {
++      compare: function() {
++        var args = Array.prototype.slice.call(arguments, 0),
++          actual = args[0],
++          expectedArgs = args.slice(1),
++          result = { pass: false };
++
++        if (!j$.isSpy(actual)) {
++          throw new Error(
++            getErrorMsg(
++              'Expected a spy, but got ' + matchersUtil.pp(actual) + '.'
++            )
++          );
++        }
++
++        if (!actual.calls.any()) {
++          result.message = function() {
++            return (
++              'Expected spy ' +
++              actual.and.identity +
++              ' to have been called with:\n' +
++              '  ' +
++              matchersUtil.pp(expectedArgs) +
++              '\nbut it was never called.'
++            );
++          };
++          return result;
++        }
++
++        if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) {
++          result.pass = true;
++          result.message = function() {
++            return (
++              'Expected spy ' +
++              actual.and.identity +
++              ' not to have been called with:\n' +
++              '  ' +
++              matchersUtil.pp(expectedArgs) +
++              '\nbut it was.'
++            );
++          };
++        } else {
++          result.message = function() {
++            var prettyPrintedCalls = actual.calls
++              .allArgs()
++              .map(function(argsForCall) {
++                return '  ' + matchersUtil.pp(argsForCall);
++              });
++
++            var diffs = actual.calls
++              .allArgs()
++              .map(function(argsForCall, callIx) {
++                var diffBuilder = new j$.DiffBuilder();
++                matchersUtil.equals(argsForCall, expectedArgs, diffBuilder);
++                return (
++                  'Call ' +
++                  callIx +
++                  ':\n' +
++                  diffBuilder.getMessage().replace(/^/gm, '  ')
++                );
++              });
++
++            return (
++              'Expected spy ' +
++              actual.and.identity +
++              ' to have been called with:\n' +
++              '  ' +
++              matchersUtil.pp(expectedArgs) +
++              '\n' +
++              '' +
++              'but actual calls were:\n' +
++              prettyPrintedCalls.join(',\n') +
++              '.\n\n' +
++              diffs.join('\n')
++            );
++          };
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toHaveBeenCalledWith;
++};
++
++getJasmineRequireObj().toHaveClass = function(j$) {
++  /**
++   * {@link expect} the actual value to be a DOM element that has the expected class
++   * @function
++   * @name matchers#toHaveClass
++   * @since 3.0.0
++   * @param {Object} expected - The class name to test for
++   * @example
++   * var el = document.createElement('div');
++   * el.className = 'foo bar baz';
++   * expect(el).toHaveClass('bar');
++   */
++  function toHaveClass(matchersUtil) {
++    return {
++      compare: function(actual, expected) {
++        if (!isElement(actual)) {
++          throw new Error(matchersUtil.pp(actual) + ' is not a DOM element');
++        }
++
++        return {
++          pass: actual.classList.contains(expected)
++        };
++      }
++    };
++  }
++
++  function isElement(maybeEl) {
++    return (
++      maybeEl && maybeEl.classList && j$.isFunction_(maybeEl.classList.contains)
++    );
++  }
++
++  return toHaveClass;
++};
++
++getJasmineRequireObj().toHaveSize = function(j$) {
++  /**
++   * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size.
++   * @function
++   * @name matchers#toHaveSize
++   * @since 3.6.0
++   * @param {Object} expected - Expected size
++   * @example
++   * array = [1,2];
++   * expect(array).toHaveSize(2);
++   */
++  function toHaveSize() {
++    return {
++      compare: function(actual, expected) {
++        var result = {
++          pass: false
++        };
++
++        if (
++          j$.isA_('WeakSet', actual) ||
++          j$.isWeakMap(actual) ||
++          j$.isDataView(actual)
++        ) {
++          throw new Error('Cannot get size of ' + actual + '.');
++        }
++
++        if (j$.isSet(actual) || j$.isMap(actual)) {
++          result.pass = actual.size === expected;
++        } else if (isLength(actual.length)) {
++          result.pass = actual.length === expected;
++        } else {
++          result.pass = Object.keys(actual).length === expected;
++        }
++
++        return result;
++      }
++    };
++  }
++
++  var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; // eslint-disable-line compat/compat
++  function isLength(value) {
++    return (
++      typeof value == 'number' &&
++      value > -1 &&
++      value % 1 === 0 &&
++      value <= MAX_SAFE_INTEGER
++    );
++  }
++
++  return toHaveSize;
++};
++
++getJasmineRequireObj().toMatch = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toMatch>',
++    'expect(<expectation>).toMatch(<string> || <regexp>)'
++  );
++
++  /**
++   * {@link expect} the actual value to match a regular expression
++   * @function
++   * @name matchers#toMatch
++   * @since 1.3.0
++   * @param {RegExp|String} expected - Value to look for in the string.
++   * @example
++   * expect("my string").toMatch(/string$/);
++   * expect("other string").toMatch("her");
++   */
++  function toMatch() {
++    return {
++      compare: function(actual, expected) {
++        if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
++          throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
++        }
++
++        var regexp = new RegExp(expected);
++
++        return {
++          pass: regexp.test(actual)
++        };
++      }
++    };
++  }
++
++  return toMatch;
++};
++
++getJasmineRequireObj().toThrow = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toThrow>',
++    'expect(function() {<expectation>}).toThrow()'
++  );
++
++  /**
++   * {@link expect} a function to `throw` something.
++   * @function
++   * @name matchers#toThrow
++   * @since 2.0.0
++   * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
++   * @example
++   * expect(function() { return 'things'; }).toThrow('foo');
++   * expect(function() { return 'stuff'; }).toThrow();
++   */
++  function toThrow(matchersUtil) {
++    return {
++      compare: function(actual, expected) {
++        var result = { pass: false },
++          threw = false,
++          thrown;
++
++        if (typeof actual != 'function') {
++          throw new Error(getErrorMsg('Actual is not a Function'));
++        }
++
++        try {
++          actual();
++        } catch (e) {
++          threw = true;
++          thrown = e;
++        }
++
++        if (!threw) {
++          result.message = 'Expected function to throw an exception.';
++          return result;
++        }
++
++        if (arguments.length == 1) {
++          result.pass = true;
++          result.message = function() {
++            return (
++              'Expected function not to throw, but it threw ' +
++              matchersUtil.pp(thrown) +
++              '.'
++            );
++          };
++
++          return result;
++        }
++
++        if (matchersUtil.equals(thrown, expected)) {
++          result.pass = true;
++          result.message = function() {
++            return (
++              'Expected function not to throw ' +
++              matchersUtil.pp(expected) +
++              '.'
++            );
++          };
++        } else {
++          result.message = function() {
++            return (
++              'Expected function to throw ' +
++              matchersUtil.pp(expected) +
++              ', but it threw ' +
++              matchersUtil.pp(thrown) +
++              '.'
++            );
++          };
++        }
++
++        return result;
++      }
++    };
++  }
++
++  return toThrow;
++};
++
++getJasmineRequireObj().toThrowError = function(j$) {
++  var getErrorMsg = j$.formatErrorMsg(
++    '<toThrowError>',
++    'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)'
++  );
++
++  /**
++   * {@link expect} a function to `throw` an `Error`.
++   * @function
++   * @name matchers#toThrowError
++   * @since 2.0.0
++   * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
++   * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
++   * @example
++   * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message');
++   * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/);
++   * expect(function() { return 'stuff'; }).toThrowError(MyCustomError);
++   * expect(function() { return 'other'; }).toThrowError(/foo/);
++   * expect(function() { return 'other'; }).toThrowError();
++   */
++  function toThrowError(matchersUtil) {
++    return {
++      compare: function(actual) {
++        var errorMatcher = getMatcher.apply(null, arguments),
++          thrown;
++
++        if (typeof actual != 'function') {
++          throw new Error(getErrorMsg('Actual is not a Function'));
++        }
++
++        try {
++          actual();
++          return fail('Expected function to throw an Error.');
++        } catch (e) {
++          thrown = e;
++        }
++
++        if (!j$.isError_(thrown)) {
++          return fail(function() {
++            return (
++              'Expected function to throw an Error, but it threw ' +
++              matchersUtil.pp(thrown) +
++              '.'
++            );
++          });
++        }
++
++        return errorMatcher.match(thrown);
++      }
++    };
++
++    function getMatcher() {
++      var expected, errorType;
++
++      if (arguments[2]) {
++        errorType = arguments[1];
++        expected = arguments[2];
++        if (!isAnErrorType(errorType)) {
++          throw new Error(getErrorMsg('Expected error type is not an Error.'));
++        }
++
++        return exactMatcher(expected, errorType);
++      } else if (arguments[1]) {
++        expected = arguments[1];
++
++        if (isAnErrorType(arguments[1])) {
++          return exactMatcher(null, arguments[1]);
++        } else {
++          return exactMatcher(arguments[1], null);
++        }
++      } else {
++        return anyMatcher();
++      }
++    }
++
++    function anyMatcher() {
++      return {
++        match: function(error) {
++          return pass(
++            'Expected function not to throw an Error, but it threw ' +
++              j$.fnNameFor(error) +
++              '.'
++          );
++        }
++      };
++    }
++
++    function exactMatcher(expected, errorType) {
++      if (expected && !isStringOrRegExp(expected)) {
++        if (errorType) {
++          throw new Error(
++            getErrorMsg('Expected error message is not a string or RegExp.')
++          );
++        } else {
++          throw new Error(
++            getErrorMsg('Expected is not an Error, string, or RegExp.')
++          );
++        }
++      }
++
++      function messageMatch(message) {
++        if (typeof expected == 'string') {
++          return expected == message;
++        } else {
++          return expected.test(message);
++        }
++      }
++
++      var errorTypeDescription = errorType
++        ? j$.fnNameFor(errorType)
++        : 'an exception';
++
++      function thrownDescription(thrown) {
++        var thrownName = errorType
++            ? j$.fnNameFor(thrown.constructor)
++            : 'an exception',
++          thrownMessage = '';
++
++        if (expected) {
++          thrownMessage = ' with message ' + matchersUtil.pp(thrown.message);
++        }
++
++        return thrownName + thrownMessage;
++      }
++
++      function messageDescription() {
++        if (expected === null) {
++          return '';
++        } else if (expected instanceof RegExp) {
++          return ' with a message matching ' + matchersUtil.pp(expected);
++        } else {
++          return ' with message ' + matchersUtil.pp(expected);
++        }
++      }
++
++      function matches(error) {
++        return (
++          (errorType === null || error instanceof errorType) &&
++          (expected === null || messageMatch(error.message))
++        );
++      }
++
++      return {
++        match: function(thrown) {
++          if (matches(thrown)) {
++            return pass(function() {
++              return (
++                'Expected function not to throw ' +
++                errorTypeDescription +
++                messageDescription() +
++                '.'
++              );
++            });
++          } else {
++            return fail(function() {
++              return (
++                'Expected function to throw ' +
++                errorTypeDescription +
++                messageDescription() +
++                ', but it threw ' +
++                thrownDescription(thrown) +
++                '.'
++              );
++            });
++          }
++        }
++      };
++    }
++
++    function isStringOrRegExp(potential) {
++      return potential instanceof RegExp || typeof potential == 'string';
++    }
++
++    function isAnErrorType(type) {
++      if (typeof type !== 'function') {
++        return false;
++      }
++
++      var Surrogate = function() {};
++      Surrogate.prototype = type.prototype;
++      return j$.isError_(new Surrogate());
++    }
++  }
++
++  function pass(message) {
++    return {
++      pass: true,
++      message: message
++    };
++  }
++
++  function fail(message) {
++    return {
++      pass: false,
++      message: message
++    };
++  }
++
++  return toThrowError;
++};
++
++getJasmineRequireObj().toThrowMatching = function(j$) {
++  var usageError = j$.formatErrorMsg(
++    '<toThrowMatching>',
++    'expect(function() {<expectation>}).toThrowMatching(<Predicate>)'
++  );
++
++  /**
++   * {@link expect} a function to `throw` something matching a predicate.
++   * @function
++   * @name matchers#toThrowMatching
++   * @since 3.0.0
++   * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches.
++   * @example
++   * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; });
++   */
++  function toThrowMatching(matchersUtil) {
++    return {
++      compare: function(actual, predicate) {
++        var thrown;
++
++        if (typeof actual !== 'function') {
++          throw new Error(usageError('Actual is not a Function'));
++        }
++
++        if (typeof predicate !== 'function') {
++          throw new Error(usageError('Predicate is not a Function'));
++        }
++
++        try {
++          actual();
++          return fail('Expected function to throw an exception.');
++        } catch (e) {
++          thrown = e;
++        }
++
++        if (predicate(thrown)) {
++          return pass(
++            'Expected function not to throw an exception matching a predicate.'
++          );
++        } else {
++          return fail(function() {
++            return (
++              'Expected function to throw an exception matching a predicate, ' +
++              'but it threw ' +
++              thrownDescription(thrown) +
++              '.'
++            );
++          });
++        }
++      }
++    };
++
++    function thrownDescription(thrown) {
++      if (thrown && thrown.constructor) {
++        return (
++          j$.fnNameFor(thrown.constructor) +
++          ' with message ' +
++          matchersUtil.pp(thrown.message)
++        );
++      } else {
++        return matchersUtil.pp(thrown);
++      }
++    }
++  }
++
++  function pass(message) {
++    return {
++      pass: true,
++      message: message
++    };
++  }
++
++  function fail(message) {
++    return {
++      pass: false,
++      message: message
++    };
++  }
++
++  return toThrowMatching;
++};
++
++getJasmineRequireObj().MockDate = function() {
++  function MockDate(global) {
++    var self = this;
++    var currentTime = 0;
++
++    if (!global || !global.Date) {
++      self.install = function() {};
++      self.tick = function() {};
++      self.uninstall = function() {};
++      return self;
++    }
++
++    var GlobalDate = global.Date;
++
++    self.install = function(mockDate) {
++      if (mockDate instanceof GlobalDate) {
++        currentTime = mockDate.getTime();
++      } else {
++        currentTime = new GlobalDate().getTime();
++      }
++
++      global.Date = FakeDate;
++    };
++
++    self.tick = function(millis) {
++      millis = millis || 0;
++      currentTime = currentTime + millis;
++    };
++
++    self.uninstall = function() {
++      currentTime = 0;
++      global.Date = GlobalDate;
++    };
++
++    createDateProperties();
++
++    return self;
++
++    function FakeDate() {
++      switch (arguments.length) {
++        case 0:
++          return new GlobalDate(currentTime);
++        case 1:
++          return new GlobalDate(arguments[0]);
++        case 2:
++          return new GlobalDate(arguments[0], arguments[1]);
++        case 3:
++          return new GlobalDate(arguments[0], arguments[1], arguments[2]);
++        case 4:
++          return new GlobalDate(
++            arguments[0],
++            arguments[1],
++            arguments[2],
++            arguments[3]
++          );
++        case 5:
++          return new GlobalDate(
++            arguments[0],
++            arguments[1],
++            arguments[2],
++            arguments[3],
++            arguments[4]
++          );
++        case 6:
++          return new GlobalDate(
++            arguments[0],
++            arguments[1],
++            arguments[2],
++            arguments[3],
++            arguments[4],
++            arguments[5]
++          );
++        default:
++          return new GlobalDate(
++            arguments[0],
++            arguments[1],
++            arguments[2],
++            arguments[3],
++            arguments[4],
++            arguments[5],
++            arguments[6]
++          );
++      }
++    }
++
++    function createDateProperties() {
++      FakeDate.prototype = GlobalDate.prototype;
++
++      FakeDate.now = function() {
++        if (GlobalDate.now) {
++          return currentTime;
++        } else {
++          throw new Error('Browser does not support Date.now()');
++        }
++      };
++
++      FakeDate.toSource = GlobalDate.toSource;
++      FakeDate.toString = GlobalDate.toString;
++      FakeDate.parse = GlobalDate.parse;
++      FakeDate.UTC = GlobalDate.UTC;
++    }
++  }
++
++  return MockDate;
++};
++
++getJasmineRequireObj().makePrettyPrinter = function(j$) {
++  function SinglePrettyPrintRun(customObjectFormatters, pp) {
++    this.customObjectFormatters_ = customObjectFormatters;
++    this.ppNestLevel_ = 0;
++    this.seen = [];
++    this.length = 0;
++    this.stringParts = [];
++    this.pp_ = pp;
++  }
++
++  function hasCustomToString(value) {
++    // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
++    // iframe, web worker)
++    try {
++      return (
++        j$.isFunction_(value.toString) &&
++        value.toString !== Object.prototype.toString &&
++        value.toString() !== Object.prototype.toString.call(value)
++      );
++    } catch (e) {
++      // The custom toString() threw.
++      return true;
++    }
++  }
++
++  SinglePrettyPrintRun.prototype.format = function(value) {
++    this.ppNestLevel_++;
++    try {
++      var customFormatResult = this.applyCustomFormatters_(value);
++
++      if (customFormatResult) {
++        this.emitScalar(customFormatResult);
++      } else if (j$.util.isUndefined(value)) {
++        this.emitScalar('undefined');
++      } else if (value === null) {
++        this.emitScalar('null');
++      } else if (value === 0 && 1 / value === -Infinity) {
++        this.emitScalar('-0');
++      } else if (value === j$.getGlobal()) {
++        this.emitScalar('<global>');
++      } else if (value.jasmineToString) {
++        this.emitScalar(value.jasmineToString(this.pp_));
++      } else if (typeof value === 'string') {
++        this.emitString(value);
++      } else if (j$.isSpy(value)) {
++        this.emitScalar('spy on ' + value.and.identity);
++      } else if (j$.isSpy(value.toString)) {
++        this.emitScalar('spy on ' + value.toString.and.identity);
++      } else if (value instanceof RegExp) {
++        this.emitScalar(value.toString());
++      } else if (typeof value === 'function') {
++        this.emitScalar('Function');
++      } else if (j$.isDomNode(value)) {
++        if (value.tagName) {
++          this.emitDomElement(value);
++        } else {
++          this.emitScalar('HTMLNode');
++        }
++      } else if (value instanceof Date) {
++        this.emitScalar('Date(' + value + ')');
++      } else if (j$.isSet(value)) {
++        this.emitSet(value);
++      } else if (j$.isMap(value)) {
++        this.emitMap(value);
++      } else if (j$.isTypedArray_(value)) {
++        this.emitTypedArray(value);
++      } else if (
++        value.toString &&
++        typeof value === 'object' &&
++        !j$.isArray_(value) &&
++        hasCustomToString(value)
++      ) {
++        try {
++          this.emitScalar(value.toString());
++        } catch (e) {
++          this.emitScalar('has-invalid-toString-method');
++        }
++      } else if (j$.util.arrayContains(this.seen, value)) {
++        this.emitScalar(
++          '<circular reference: ' +
++            (j$.isArray_(value) ? 'Array' : 'Object') +
++            '>'
++        );
++      } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
++        this.seen.push(value);
++        if (j$.isArray_(value)) {
++          this.emitArray(value);
++        } else {
++          this.emitObject(value);
++        }
++        this.seen.pop();
++      } else {
++        this.emitScalar(value.toString());
++      }
++    } catch (e) {
++      if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
++        throw e;
++      }
++    } finally {
++      this.ppNestLevel_--;
++    }
++  };
++
++  SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
++    return customFormat(value, this.customObjectFormatters_);
++  };
++
++  SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
++    var objKeys = keys(obj, j$.isArray_(obj));
++    var isGetter = function isGetter(prop) {};
++
++    if (obj.__lookupGetter__) {
++      isGetter = function isGetter(prop) {
++        var getter = obj.__lookupGetter__(prop);
++        return !j$.util.isUndefined(getter) && getter !== null;
++      };
++    }
++    var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
++    for (var i = 0; i < length; i++) {
++      var property = objKeys[i];
++      fn(property, isGetter(property));
++    }
++
++    return objKeys.length > length;
++  };
++
++  SinglePrettyPrintRun.prototype.emitScalar = function(value) {
++    this.append(value);
++  };
++
++  SinglePrettyPrintRun.prototype.emitString = function(value) {
++    this.append("'" + value + "'");
++  };
++
++  SinglePrettyPrintRun.prototype.emitArray = function(array) {
++    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
++      this.append('Array');
++      return;
++    }
++    var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
++    this.append('[ ');
++    for (var i = 0; i < length; i++) {
++      if (i > 0) {
++        this.append(', ');
++      }
++      this.format(array[i]);
++    }
++    if (array.length > length) {
++      this.append(', ...');
++    }
++
++    var self = this;
++    var first = array.length === 0;
++    var truncated = this.iterateObject(array, function(property, isGetter) {
++      if (first) {
++        first = false;
++      } else {
++        self.append(', ');
++      }
++
++      self.formatProperty(array, property, isGetter);
++    });
++
++    if (truncated) {
++      this.append(', ...');
++    }
++
++    this.append(' ]');
++  };
++
++  SinglePrettyPrintRun.prototype.emitSet = function(set) {
++    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
++      this.append('Set');
++      return;
++    }
++    this.append('Set( ');
++    var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
++    var i = 0;
++    set.forEach(function(value, key) {
++      if (i >= size) {
++        return;
++      }
++      if (i > 0) {
++        this.append(', ');
++      }
++      this.format(value);
++
++      i++;
++    }, this);
++    if (set.size > size) {
++      this.append(', ...');
++    }
++    this.append(' )');
++  };
++
++  SinglePrettyPrintRun.prototype.emitMap = function(map) {
++    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
++      this.append('Map');
++      return;
++    }
++    this.append('Map( ');
++    var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
++    var i = 0;
++    map.forEach(function(value, key) {
++      if (i >= size) {
++        return;
++      }
++      if (i > 0) {
++        this.append(', ');
++      }
++      this.format([key, value]);
++
++      i++;
++    }, this);
++    if (map.size > size) {
++      this.append(', ...');
++    }
++    this.append(' )');
++  };
++
++  SinglePrettyPrintRun.prototype.emitObject = function(obj) {
++    var ctor = obj.constructor,
++      constructorName;
++
++    constructorName =
++      typeof ctor === 'function' && obj instanceof ctor
++        ? j$.fnNameFor(obj.constructor)
++        : 'null';
++
++    this.append(constructorName);
++
++    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
++      return;
++    }
++
++    var self = this;
++    this.append('({ ');
++    var first = true;
++
++    var truncated = this.iterateObject(obj, function(property, isGetter) {
++      if (first) {
++        first = false;
++      } else {
++        self.append(', ');
++      }
++
++      self.formatProperty(obj, property, isGetter);
++    });
++
++    if (truncated) {
++      this.append(', ...');
++    }
++
++    this.append(' })');
++  };
++
++  SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) {
++    var constructorName = j$.fnNameFor(arr.constructor),
++      limitedArray = Array.prototype.slice.call(
++        arr,
++        0,
++        j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
++      ),
++      itemsString = Array.prototype.join.call(limitedArray, ', ');
++
++    if (limitedArray.length !== arr.length) {
++      itemsString += ', ...';
++    }
++
++    this.append(constructorName + ' [ ' + itemsString + ' ]');
++  };
++
++  SinglePrettyPrintRun.prototype.emitDomElement = function(el) {
++    var tagName = el.tagName.toLowerCase(),
++      attrs = el.attributes,
++      i,
++      len = attrs.length,
++      out = '<' + tagName,
++      attr;
++
++    for (i = 0; i < len; i++) {
++      attr = attrs[i];
++      out += ' ' + attr.name;
++
++      if (attr.value !== '') {
++        out += '="' + attr.value + '"';
++      }
++    }
++
++    out += '>';
++
++    if (el.childElementCount !== 0 || el.textContent !== '') {
++      out += '...</' + tagName + '>';
++    }
++
++    this.append(out);
++  };
++
++  SinglePrettyPrintRun.prototype.formatProperty = function(
++    obj,
++    property,
++    isGetter
++  ) {
++    this.append(property);
++    this.append(': ');
++    if (isGetter) {
++      this.append('<getter>');
++    } else {
++      this.format(obj[property]);
++    }
++  };
++
++  SinglePrettyPrintRun.prototype.append = function(value) {
++    // This check protects us from the rare case where an object has overriden
++    // `toString()` with an invalid implementation (returning a non-string).
++    if (typeof value !== 'string') {
++      value = Object.prototype.toString.call(value);
++    }
++
++    var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
++    this.length += result.value.length;
++    this.stringParts.push(result.value);
++
++    if (result.truncated) {
++      throw new MaxCharsReachedError();
++    }
++  };
++
++  function truncate(s, maxlen) {
++    if (s.length <= maxlen) {
++      return { value: s, truncated: false };
++    }
++
++    s = s.substring(0, maxlen - 4) + ' ...';
++    return { value: s, truncated: true };
++  }
++
++  function MaxCharsReachedError() {
++    this.message =
++      'Exceeded ' +
++      j$.MAX_PRETTY_PRINT_CHARS +
++      ' characters while pretty-printing a value';
++  }
++
++  MaxCharsReachedError.prototype = new Error();
++
++  function keys(obj, isArray) {
++    var allKeys = Object.keys
++      ? Object.keys(obj)
++      : (function(o) {
++          var keys = [];
++          for (var key in o) {
++            if (j$.util.has(o, key)) {
++              keys.push(key);
++            }
++          }
++          return keys;
++        })(obj);
++
++    if (!isArray) {
++      return allKeys;
++    }
++
++    if (allKeys.length === 0) {
++      return allKeys;
++    }
++
++    var extraKeys = [];
++    for (var i = 0; i < allKeys.length; i++) {
++      if (!/^[0-9]+$/.test(allKeys[i])) {
++        extraKeys.push(allKeys[i]);
++      }
++    }
++
++    return extraKeys;
++  }
++
++  function customFormat(value, customObjectFormatters) {
++    var i, result;
++
++    for (i = 0; i < customObjectFormatters.length; i++) {
++      result = customObjectFormatters[i](value);
++
++      if (result !== undefined) {
++        return result;
++      }
++    }
++  }
++
++  return function(customObjectFormatters) {
++    customObjectFormatters = customObjectFormatters || [];
++
++    var pp = function(value) {
++      var prettyPrinter = new SinglePrettyPrintRun(customObjectFormatters, pp);
++      prettyPrinter.format(value);
++      return prettyPrinter.stringParts.join('');
++    };
++
++    pp.customFormat_ = function(value) {
++      return customFormat(value, customObjectFormatters);
++    };
++
++    return pp;
++  };
++};
++
++getJasmineRequireObj().QueueRunner = function(j$) {
++  var nextid = 1;
++
++  function StopExecutionError() {}
++  StopExecutionError.prototype = new Error();
++  j$.StopExecutionError = StopExecutionError;
++
++  function once(fn) {
++    var called = false;
++    return function(arg) {
++      if (!called) {
++        called = true;
++        // Direct call using single parameter, because cleanup/next does not need more
++        fn(arg);
++      }
++      return null;
++    };
++  }
++
++  function emptyFn() {}
++
++  function QueueRunner(attrs) {
++    this.id_ = nextid++;
++    var queueableFns = attrs.queueableFns || [];
++    this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
++    this.firstCleanupIx = queueableFns.length;
++    this.onComplete = attrs.onComplete || emptyFn;
++    this.clearStack =
++      attrs.clearStack ||
++      function(fn) {
++        fn();
++      };
++    this.onException = attrs.onException || emptyFn;
++    this.userContext = attrs.userContext || new j$.UserContext();
++    this.timeout = attrs.timeout || {
++      setTimeout: setTimeout,
++      clearTimeout: clearTimeout
++    };
++    this.fail = attrs.fail || emptyFn;
++    this.globalErrors = attrs.globalErrors || {
++      pushListener: emptyFn,
++      popListener: emptyFn
++    };
++    this.completeOnFirstError = !!attrs.completeOnFirstError;
++    this.errored = false;
++
++    if (typeof this.onComplete !== 'function') {
++      throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
++    }
++    this.deprecated = attrs.deprecated;
++  }
++
++  QueueRunner.prototype.execute = function() {
++    var self = this;
++    this.handleFinalError = function(message, source, lineno, colno, error) {
++      // Older browsers would send the error as the first parameter. HTML5
++      // specifies the the five parameters above. The error instance should
++      // be preffered, otherwise the call stack would get lost.
++      self.onException(error || message);
++    };
++    this.globalErrors.pushListener(this.handleFinalError);
++    this.run(0);
++  };
++
++  QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
++    if (lastRanIndex < this.firstCleanupIx) {
++      this.run(this.firstCleanupIx);
++    } else {
++      this.run(lastRanIndex + 1);
++    }
++  };
++
++  QueueRunner.prototype.clearTimeout = function(timeoutId) {
++    Function.prototype.apply.apply(this.timeout.clearTimeout, [
++      j$.getGlobal(),
++      [timeoutId]
++    ]);
++  };
++
++  QueueRunner.prototype.setTimeout = function(fn, timeout) {
++    return Function.prototype.apply.apply(this.timeout.setTimeout, [
++      j$.getGlobal(),
++      [fn, timeout]
++    ]);
++  };
++
++  QueueRunner.prototype.attempt = function attempt(iterativeIndex) {
++    var self = this,
++      completedSynchronously = true,
++      handleError = function handleError(error) {
++        onException(error);
++      },
++      cleanup = once(function cleanup() {
++        if (timeoutId !== void 0) {
++          self.clearTimeout(timeoutId);
++        }
++        self.globalErrors.popListener(handleError);
++      }),
++      next = once(function next(err) {
++        cleanup();
++
++        if (j$.isError_(err)) {
++          if (!(err instanceof StopExecutionError) && !err.jasmineMessage) {
++            self.fail(err);
++          }
++          self.errored = errored = true;
++        }
++
++        function runNext() {
++          if (self.completeOnFirstError && errored) {
++            self.skipToCleanup(iterativeIndex);
++          } else {
++            self.run(iterativeIndex + 1);
++          }
++        }
++
++        if (completedSynchronously) {
++          self.setTimeout(runNext);
++        } else {
++          runNext();
++        }
++      }),
++      errored = false,
++      queueableFn = self.queueableFns[iterativeIndex],
++      timeoutId,
++      maybeThenable;
++
++    next.fail = function nextFail() {
++      self.fail.apply(null, arguments);
++      self.errored = errored = true;
++      next();
++    };
++
++    self.globalErrors.pushListener(handleError);
++
++    if (queueableFn.timeout !== undefined) {
++      var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
++      timeoutId = self.setTimeout(function() {
++        var error = new Error(
++          'Timeout - Async function did not complete within ' +
++            timeoutInterval +
++            'ms ' +
++            (queueableFn.timeout
++              ? '(custom timeout)'
++              : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
++        );
++        onException(error);
++        next();
++      }, timeoutInterval);
++    }
++
++    try {
++      if (queueableFn.fn.length === 0) {
++        maybeThenable = queueableFn.fn.call(self.userContext);
++
++        if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
++          maybeThenable.then(next, onPromiseRejection);
++          completedSynchronously = false;
++          return { completedSynchronously: false };
++        }
++      } else {
++        maybeThenable = queueableFn.fn.call(self.userContext, next);
++        this.diagnoseConflictingAsync_(queueableFn.fn, maybeThenable);
++        completedSynchronously = false;
++        return { completedSynchronously: false };
++      }
++    } catch (e) {
++      onException(e);
++      self.errored = errored = true;
++    }
++
++    cleanup();
++    return { completedSynchronously: true, errored: errored };
++
++    function onException(e) {
++      self.onException(e);
++      self.errored = errored = true;
++    }
++
++    function onPromiseRejection(e) {
++      onException(e);
++      next();
++    }
++  };
++
++  QueueRunner.prototype.run = function(recursiveIndex) {
++    var length = this.queueableFns.length,
++      self = this,
++      iterativeIndex;
++
++    for (
++      iterativeIndex = recursiveIndex;
++      iterativeIndex < length;
++      iterativeIndex++
++    ) {
++      var result = this.attempt(iterativeIndex);
++
++      if (!result.completedSynchronously) {
++        return;
++      }
++
++      self.errored = self.errored || result.errored;
++
++      if (this.completeOnFirstError && result.errored) {
++        this.skipToCleanup(iterativeIndex);
++        return;
++      }
++    }
++
++    this.clearStack(function() {
++      self.globalErrors.popListener(self.handleFinalError);
++      self.onComplete(self.errored && new StopExecutionError());
++    });
++  };
++
++  QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) {
++    if (retval && j$.isFunction_(retval.then)) {
++      // Issue a warning that matches the user's code
++      if (j$.isAsyncFunction_(fn)) {
++        this.deprecated(
++          'An asynchronous before/it/after ' +
++            'function was defined with the async keyword but also took a ' +
++            'done callback. This is not supported and will stop working in' +
++            ' the future. Either remove the done callback (recommended) or ' +
++            'remove the async keyword.'
++        );
++      } else {
++        this.deprecated(
++          'An asynchronous before/it/after ' +
++            'function took a done callback but also returned a promise. ' +
++            'This is not supported and will stop working in the future. ' +
++            'Either remove the done callback (recommended) or change the ' +
++            'function to not return a promise.'
++        );
++      }
++    }
++  };
++
++  return QueueRunner;
++};
++
++getJasmineRequireObj().ReportDispatcher = function(j$) {
++  function ReportDispatcher(methods, queueRunnerFactory) {
++    var dispatchedMethods = methods || [];
++
++    for (var i = 0; i < dispatchedMethods.length; i++) {
++      var method = dispatchedMethods[i];
++      this[method] = (function(m) {
++        return function() {
++          dispatch(m, arguments);
++        };
++      })(method);
++    }
++
++    var reporters = [];
++    var fallbackReporter = null;
++
++    this.addReporter = function(reporter) {
++      reporters.push(reporter);
++    };
++
++    this.provideFallbackReporter = function(reporter) {
++      fallbackReporter = reporter;
++    };
++
++    this.clearReporters = function() {
++      reporters = [];
++    };
++
++    return this;
++
++    function dispatch(method, args) {
++      if (reporters.length === 0 && fallbackReporter !== null) {
++        reporters.push(fallbackReporter);
++      }
++      var onComplete = args[args.length - 1];
++      args = j$.util.argsToArray(args).splice(0, args.length - 1);
++      var fns = [];
++      for (var i = 0; i < reporters.length; i++) {
++        var reporter = reporters[i];
++        addFn(fns, reporter, method, args);
++      }
++
++      queueRunnerFactory({
++        queueableFns: fns,
++        onComplete: onComplete,
++        isReporter: true
++      });
++    }
++
++    function addFn(fns, reporter, method, args) {
++      var fn = reporter[method];
++      if (!fn) {
++        return;
++      }
++
++      var thisArgs = j$.util.cloneArgs(args);
++      if (fn.length <= 1) {
++        fns.push({
++          fn: function() {
++            return fn.apply(reporter, thisArgs);
++          }
++        });
++      } else {
++        fns.push({
++          fn: function(done) {
++            return fn.apply(reporter, thisArgs.concat([done]));
++          }
++        });
++      }
++    }
++  }
++
++  return ReportDispatcher;
++};
++
++getJasmineRequireObj().interface = function(jasmine, env) {
++  var jasmineInterface = {
++    /**
++     * Callback passed to parts of the Jasmine base interface.
++     *
++     * By default Jasmine assumes this function completes synchronously.
++     * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment.
++     * @callback implementationCallback
++     * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
++     * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
++     */
++
++    /**
++     * Create a group of specs (often called a suite).
++     *
++     * Calls to `describe` can be nested within other calls to compose your suite as a tree.
++     * @name describe
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {String} description Textual description of the group
++     * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
++     */
++    describe: function(description, specDefinitions) {
++      return env.describe(description, specDefinitions);
++    },
++
++    /**
++     * A temporarily disabled [`describe`]{@link describe}
++     *
++     * Specs within an `xdescribe` will be marked pending and not executed
++     * @name xdescribe
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {String} description Textual description of the group
++     * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
++     */
++    xdescribe: function(description, specDefinitions) {
++      return env.xdescribe(description, specDefinitions);
++    },
++
++    /**
++     * A focused [`describe`]{@link describe}
++     *
++     * If suites or specs are focused, only those that are focused will be executed
++     * @see fit
++     * @name fdescribe
++     * @since 2.1.0
++     * @function
++     * @global
++     * @param {String} description Textual description of the group
++     * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
++     */
++    fdescribe: function(description, specDefinitions) {
++      return env.fdescribe(description, specDefinitions);
++    },
++
++    /**
++     * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
++     *
++     * A spec whose expectations all succeed will be passing and a spec with any failures will fail.
++     * The name `it` is a pronoun for the test target, not an abbreviation of anything. It makes the
++     * spec more readable by connecting the function name `it` and the argument `description` as a
++     * complete sentence.
++     * @name it
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {String} description Textual description of what this spec is checking
++     * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
++     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
++     * @see async
++     */
++    it: function() {
++      return env.it.apply(env, arguments);
++    },
++
++    /**
++     * A temporarily disabled [`it`]{@link it}
++     *
++     * The spec will report as `pending` and will not be executed.
++     * @name xit
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {String} description Textual description of what this spec is checking.
++     * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed.
++     */
++    xit: function() {
++      return env.xit.apply(env, arguments);
++    },
++
++    /**
++     * A focused [`it`]{@link it}
++     *
++     * If suites or specs are focused, only those that are focused will be executed.
++     * @name fit
++     * @since 2.1.0
++     * @function
++     * @global
++     * @param {String} description Textual description of what this spec is checking.
++     * @param {implementationCallback} testFunction Function that contains the code of your test.
++     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
++     * @see async
++     */
++    fit: function() {
++      return env.fit.apply(env, arguments);
++    },
++
++    /**
++     * Run some shared setup before each of the specs in the {@link describe} in which it is called.
++     * @name beforeEach
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {implementationCallback} [function] Function that contains the code to setup your specs.
++     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
++     * @see async
++     */
++    beforeEach: function() {
++      return env.beforeEach.apply(env, arguments);
++    },
++
++    /**
++     * Run some shared teardown after each of the specs in the {@link describe} in which it is called.
++     * @name afterEach
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
++     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
++     * @see async
++     */
++    afterEach: function() {
++      return env.afterEach.apply(env, arguments);
++    },
++
++    /**
++     * Run some shared setup once before all of the specs in the {@link describe} are run.
++     *
++     * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
++     * @name beforeAll
++     * @since 2.1.0
++     * @function
++     * @global
++     * @param {implementationCallback} [function] Function that contains the code to setup your specs.
++     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
++     * @see async
++     */
++    beforeAll: function() {
++      return env.beforeAll.apply(env, arguments);
++    },
++
++    /**
++     * Run some shared teardown once after all of the specs in the {@link describe} are run.
++     *
++     * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
++     * @name afterAll
++     * @since 2.1.0
++     * @function
++     * @global
++     * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
++     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
++     * @see async
++     */
++    afterAll: function() {
++      return env.afterAll.apply(env, arguments);
++    },
++
++    /**
++     * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult}
++     * @name setSpecProperty
++     * @since 3.6.0
++     * @function
++     * @param {String} key The name of the property
++     * @param {*} value The value of the property
++     */
++    setSpecProperty: function(key, value) {
++      return env.setSpecProperty(key, value);
++    },
++
++    /**
++     * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult}
++     * @name setSuiteProperty
++     * @since 3.6.0
++     * @function
++     * @param {String} key The name of the property
++     * @param {*} value The value of the property
++     */
++    setSuiteProperty: function(key, value) {
++      return env.setSuiteProperty(key, value);
++    },
++
++    /**
++     * Create an expectation for a spec.
++     * @name expect
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {Object} actual - Actual computed value to test expectations against.
++     * @return {matchers}
++     */
++    expect: function(actual) {
++      return env.expect(actual);
++    },
++
++    /**
++     * Create an asynchronous expectation for a spec. Note that the matchers
++     * that are provided by an asynchronous expectation all return promises
++     * which must be either returned from the spec or waited for using `await`
++     * in order for Jasmine to associate them with the correct spec.
++     * @name expectAsync
++     * @since 3.3.0
++     * @function
++     * @global
++     * @param {Object} actual - Actual computed value to test expectations against.
++     * @return {async-matchers}
++     * @example
++     * await expectAsync(somePromise).toBeResolved();
++     * @example
++     * return expectAsync(somePromise).toBeResolved();
++     */
++    expectAsync: function(actual) {
++      return env.expectAsync(actual);
++    },
++
++    /**
++     * Mark a spec as pending, expectation results will be ignored.
++     * @name pending
++     * @since 2.0.0
++     * @function
++     * @global
++     * @param {String} [message] - Reason the spec is pending.
++     */
++    pending: function() {
++      return env.pending.apply(env, arguments);
++    },
++
++    /**
++     * Explicitly mark a spec as failed.
++     * @name fail
++     * @since 2.1.0
++     * @function
++     * @global
++     * @param {String|Error} [error] - Reason for the failure.
++     */
++    fail: function() {
++      return env.fail.apply(env, arguments);
++    },
++
++    /**
++     * Install a spy onto an existing object.
++     * @name spyOn
++     * @since 1.3.0
++     * @function
++     * @global
++     * @param {Object} obj - The object upon which to install the {@link Spy}.
++     * @param {String} methodName - The name of the method to replace with a {@link Spy}.
++     * @returns {Spy}
++     */
++    spyOn: function(obj, methodName) {
++      return env.spyOn(obj, methodName);
++    },
++
++    /**
++     * Install a spy on a property installed with `Object.defineProperty` onto an existing object.
++     * @name spyOnProperty
++     * @since 2.6.0
++     * @function
++     * @global
++     * @param {Object} obj - The object upon which to install the {@link Spy}
++     * @param {String} propertyName - The name of the property to replace with a {@link Spy}.
++     * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on.
++     * @returns {Spy}
++     */
++    spyOnProperty: function(obj, methodName, accessType) {
++      return env.spyOnProperty(obj, methodName, accessType);
++    },
++
++    /**
++     * Installs spies on all writable and configurable properties of an object.
++     * @name spyOnAllFunctions
++     * @since 3.2.1
++     * @function
++     * @global
++     * @param {Object} obj - The object upon which to install the {@link Spy}s
++     * @param {boolean} includeNonEnumerable - Whether or not to add spies to non-enumerable properties
++     * @returns {Object} the spied object
++     */
++    spyOnAllFunctions: function(obj, includeNonEnumerable) {
++      return env.spyOnAllFunctions(obj, includeNonEnumerable);
++    },
++
++    jsApiReporter: new jasmine.JsApiReporter({
++      timer: new jasmine.Timer()
++    }),
++
++    /**
++     * @namespace jasmine
++     */
++    jasmine: jasmine
++  };
++
++  /**
++   * Add a custom equality tester for the current scope of specs.
++   *
++   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
++   * @name jasmine.addCustomEqualityTester
++   * @since 2.0.0
++   * @function
++   * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise.
++   * @see custom_equality
++   */
++  jasmine.addCustomEqualityTester = function(tester) {
++    env.addCustomEqualityTester(tester);
++  };
++
++  /**
++   * Add custom matchers for the current scope of specs.
++   *
++   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
++   * @name jasmine.addMatchers
++   * @since 2.0.0
++   * @function
++   * @param {Object} matchers - Keys from this object will be the new matcher names.
++   * @see custom_matcher
++   */
++  jasmine.addMatchers = function(matchers) {
++    return env.addMatchers(matchers);
++  };
++
++  /**
++   * Add custom async matchers for the current scope of specs.
++   *
++   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
++   * @name jasmine.addAsyncMatchers
++   * @since 3.5.0
++   * @function
++   * @param {Object} matchers - Keys from this object will be the new async matcher names.
++   * @see custom_matcher
++   */
++  jasmine.addAsyncMatchers = function(matchers) {
++    return env.addAsyncMatchers(matchers);
++  };
++
++  /**
++   * Add a custom object formatter for the current scope of specs.
++   *
++   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
++   * @name jasmine.addCustomObjectFormatter
++   * @since 3.6.0
++   * @function
++   * @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise.
++   * @see custom_object_formatters
++   */
++  jasmine.addCustomObjectFormatter = function(formatter) {
++    return env.addCustomObjectFormatter(formatter);
++  };
++
++  /**
++   * Get the currently booted mock {Clock} for this Jasmine environment.
++   * @name jasmine.clock
++   * @since 2.0.0
++   * @function
++   * @returns {Clock}
++   */
++  jasmine.clock = function() {
++    return env.clock;
++  };
++
++  /**
++   * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
++   * @name jasmine.createSpy
++   * @since 1.3.0
++   * @function
++   * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
++   * @param {Function} [originalFn] - Function to act as the real implementation.
++   * @return {Spy}
++   */
++  jasmine.createSpy = function(name, originalFn) {
++    return env.createSpy(name, originalFn);
++  };
++
++  /**
++   * Create an object with multiple {@link Spy}s as its members.
++   * @name jasmine.createSpyObj
++   * @since 1.3.0
++   * @function
++   * @param {String} [baseName] - Base name for the spies in the object.
++   * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
++   * @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}.
++   * @return {Object}
++   */
++  jasmine.createSpyObj = function(baseName, methodNames, propertyNames) {
++    return env.createSpyObj(baseName, methodNames, propertyNames);
++  };
++
++  /**
++   * Add a custom spy strategy for the current scope of specs.
++   *
++   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
++   * @name jasmine.addSpyStrategy
++   * @since 3.5.0
++   * @function
++   * @param {String} name - The name of the strategy (i.e. what you call from `and`)
++   * @param {Function} factory - Factory function that returns the plan to be executed.
++   */
++  jasmine.addSpyStrategy = function(name, factory) {
++    return env.addSpyStrategy(name, factory);
++  };
++
++  /**
++   * Set the default spy strategy for the current scope of specs.
++   *
++   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
++   * @name jasmine.setDefaultSpyStrategy
++   * @function
++   * @param {Function} defaultStrategyFn - a function that assigns a strategy
++   * @example
++   * beforeEach(function() {
++   *   jasmine.setDefaultSpyStrategy(and => and.returnValue(true));
++   * });
++   */
++  jasmine.setDefaultSpyStrategy = function(defaultStrategyFn) {
++    return env.setDefaultSpyStrategy(defaultStrategyFn);
++  };
++
++  return jasmineInterface;
++};
++
++getJasmineRequireObj().Spy = function(j$) {
++  var nextOrder = (function() {
++    var order = 0;
++
++    return function() {
++      return order++;
++    };
++  })();
++
++  var matchersUtil = new j$.MatchersUtil({
++    customTesters: [],
++    pp: j$.makePrettyPrinter()
++  });
++
++  /**
++   * @classdesc _Note:_ Do not construct this directly. Use {@link spyOn},
++   * {@link spyOnProperty}, {@link jasmine.createSpy}, or
++   * {@link jasmine.createSpyObj} instead.
++   * @class Spy
++   * @hideconstructor
++   */
++  function Spy(
++    name,
++    originalFn,
++    customStrategies,
++    defaultStrategyFn,
++    getPromise
++  ) {
++    var numArgs = typeof originalFn === 'function' ? originalFn.length : 0,
++      wrapper = makeFunc(numArgs, function(context, args, invokeNew) {
++        return spy(context, args, invokeNew);
++      }),
++      strategyDispatcher = new SpyStrategyDispatcher({
++        name: name,
++        fn: originalFn,
++        getSpy: function() {
++          return wrapper;
++        },
++        customStrategies: customStrategies,
++        getPromise: getPromise
++      }),
++      callTracker = new j$.CallTracker(),
++      spy = function(context, args, invokeNew) {
++        /**
++         * @name Spy.callData
++         * @property {object} object - `this` context for the invocation.
++         * @property {number} invocationOrder - Order of the invocation.
++         * @property {Array} args - The arguments passed for this invocation.
++         * @property returnValue - The value that was returned from this invocation.
++         */
++        var callData = {
++          object: context,
++          invocationOrder: nextOrder(),
++          args: Array.prototype.slice.apply(args)
++        };
++
++        callTracker.track(callData);
++        var returnValue = strategyDispatcher.exec(context, args, invokeNew);
++        callData.returnValue = returnValue;
++
++        return returnValue;
++      };
++
++    function makeFunc(length, fn) {
++      switch (length) {
++        case 1:
++          return function wrap1(a) {
++            return fn(this, arguments, this instanceof wrap1);
++          };
++        case 2:
++          return function wrap2(a, b) {
++            return fn(this, arguments, this instanceof wrap2);
++          };
++        case 3:
++          return function wrap3(a, b, c) {
++            return fn(this, arguments, this instanceof wrap3);
++          };
++        case 4:
++          return function wrap4(a, b, c, d) {
++            return fn(this, arguments, this instanceof wrap4);
++          };
++        case 5:
++          return function wrap5(a, b, c, d, e) {
++            return fn(this, arguments, this instanceof wrap5);
++          };
++        case 6:
++          return function wrap6(a, b, c, d, e, f) {
++            return fn(this, arguments, this instanceof wrap6);
++          };
++        case 7:
++          return function wrap7(a, b, c, d, e, f, g) {
++            return fn(this, arguments, this instanceof wrap7);
++          };
++        case 8:
++          return function wrap8(a, b, c, d, e, f, g, h) {
++            return fn(this, arguments, this instanceof wrap8);
++          };
++        case 9:
++          return function wrap9(a, b, c, d, e, f, g, h, i) {
++            return fn(this, arguments, this instanceof wrap9);
++          };
++        default:
++          return function wrap() {
++            return fn(this, arguments, this instanceof wrap);
++          };
++      }
++    }
++
++    for (var prop in originalFn) {
++      if (prop === 'and' || prop === 'calls') {
++        throw new Error(
++          "Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon"
++        );
++      }
++
++      wrapper[prop] = originalFn[prop];
++    }
++
++    /**
++     * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used
++     * whenever the spy is called with arguments that don't match any strategy
++     * created with {@link Spy#withArgs}.
++     * @name Spy#and
++     * @since 2.0.0
++     * @example
++     * spyOn(someObj, 'func').and.returnValue(42);
++     */
++    wrapper.and = strategyDispatcher.and;
++    /**
++     * Specifies a strategy to be used for calls to the spy that have the
++     * specified arguments.
++     * @name Spy#withArgs
++     * @since 3.0.0
++     * @function
++     * @param {...*} args - The arguments to match
++     * @type {SpyStrategy}
++     * @example
++     * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42);
++     * someObj.func(1, 2, 3); // returns 42
++     */
++    wrapper.withArgs = function() {
++      return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments);
++    };
++    wrapper.calls = callTracker;
++
++    if (defaultStrategyFn) {
++      defaultStrategyFn(wrapper.and);
++    }
++
++    return wrapper;
++  }
++
++  function SpyStrategyDispatcher(strategyArgs) {
++    var baseStrategy = new j$.SpyStrategy(strategyArgs);
++    var argsStrategies = new StrategyDict(function() {
++      return new j$.SpyStrategy(strategyArgs);
++    });
++
++    this.and = baseStrategy;
++
++    this.exec = function(spy, args, invokeNew) {
++      var strategy = argsStrategies.get(args);
++
++      if (!strategy) {
++        if (argsStrategies.any() && !baseStrategy.isConfigured()) {
++          throw new Error(
++            "Spy '" +
++              strategyArgs.name +
++              "' received a call with arguments " +
++              j$.pp(Array.prototype.slice.call(args)) +
++              ' but all configured strategies specify other arguments.'
++          );
++        } else {
++          strategy = baseStrategy;
++        }
++      }
++
++      return strategy.exec(spy, args, invokeNew);
++    };
++
++    this.withArgs = function() {
++      return { and: argsStrategies.getOrCreate(arguments) };
++    };
++  }
++
++  function StrategyDict(strategyFactory) {
++    this.strategies = [];
++    this.strategyFactory = strategyFactory;
++  }
++
++  StrategyDict.prototype.any = function() {
++    return this.strategies.length > 0;
++  };
++
++  StrategyDict.prototype.getOrCreate = function(args) {
++    var strategy = this.get(args);
++
++    if (!strategy) {
++      strategy = this.strategyFactory();
++      this.strategies.push({
++        args: args,
++        strategy: strategy
++      });
++    }
++
++    return strategy;
++  };
++
++  StrategyDict.prototype.get = function(args) {
++    var i;
++
++    for (i = 0; i < this.strategies.length; i++) {
++      if (matchersUtil.equals(args, this.strategies[i].args)) {
++        return this.strategies[i].strategy;
++      }
++    }
++  };
++
++  return Spy;
++};
++
++getJasmineRequireObj().SpyFactory = function(j$) {
++  function SpyFactory(getCustomStrategies, getDefaultStrategyFn, getPromise) {
++    var self = this;
++
++    this.createSpy = function(name, originalFn) {
++      return j$.Spy(
++        name,
++        originalFn,
++        getCustomStrategies(),
++        getDefaultStrategyFn(),
++        getPromise
++      );
++    };
++
++    this.createSpyObj = function(baseName, methodNames, propertyNames) {
++      var baseNameIsCollection =
++        j$.isObject_(baseName) || j$.isArray_(baseName);
++
++      if (baseNameIsCollection) {
++        propertyNames = methodNames;
++        methodNames = baseName;
++        baseName = 'unknown';
++      }
++
++      var obj = {};
++      var spy, descriptor;
++
++      var methods = normalizeKeyValues(methodNames);
++      for (var i = 0; i < methods.length; i++) {
++        spy = obj[methods[i][0]] = self.createSpy(
++          baseName + '.' + methods[i][0]
++        );
++        if (methods[i].length > 1) {
++          spy.and.returnValue(methods[i][1]);
++        }
++      }
++
++      var properties = normalizeKeyValues(propertyNames);
++      for (var i = 0; i < properties.length; i++) {
++        descriptor = {
++          enumerable: true,
++          get: self.createSpy(baseName + '.' + properties[i][0] + '.get'),
++          set: self.createSpy(baseName + '.' + properties[i][0] + '.set')
++        };
++        if (properties[i].length > 1) {
++          descriptor.get.and.returnValue(properties[i][1]);
++          descriptor.set.and.returnValue(properties[i][1]);
++        }
++        Object.defineProperty(obj, properties[i][0], descriptor);
++      }
++
++      if (methods.length === 0 && properties.length === 0) {
++        throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
++      }
++
++      return obj;
++    };
++  }
++
++  function normalizeKeyValues(object) {
++    var result = [];
++    if (j$.isArray_(object)) {
++      for (var i = 0; i < object.length; i++) {
++        result.push([object[i]]);
++      }
++    } else if (j$.isObject_(object)) {
++      for (var key in object) {
++        if (object.hasOwnProperty(key)) {
++          result.push([key, object[key]]);
++        }
++      }
++    }
++    return result;
++  }
++
++  return SpyFactory;
++};
++
++getJasmineRequireObj().SpyRegistry = function(j$) {
++  var spyOnMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
++  var spyOnPropertyMsg = j$.formatErrorMsg(
++    '<spyOnProperty>',
++    'spyOnProperty(<object>, <propName>, [accessType])'
++  );
++
++  function SpyRegistry(options) {
++    options = options || {};
++    var global = options.global || j$.getGlobal();
++    var createSpy = options.createSpy;
++    var currentSpies =
++      options.currentSpies ||
++      function() {
++        return [];
++      };
++
++    this.allowRespy = function(allow) {
++      this.respy = allow;
++    };
++
++    this.spyOn = function(obj, methodName) {
++      var getErrorMsg = spyOnMsg;
++
++      if (j$.util.isUndefined(obj) || obj === null) {
++        throw new Error(
++          getErrorMsg(
++            'could not find an object to spy upon for ' + methodName + '()'
++          )
++        );
++      }
++
++      if (j$.util.isUndefined(methodName) || methodName === null) {
++        throw new Error(getErrorMsg('No method name supplied'));
++      }
++
++      if (j$.util.isUndefined(obj[methodName])) {
++        throw new Error(getErrorMsg(methodName + '() method does not exist'));
++      }
++
++      if (obj[methodName] && j$.isSpy(obj[methodName])) {
++        if (this.respy) {
++          return obj[methodName];
++        } else {
++          throw new Error(
++            getErrorMsg(methodName + ' has already been spied upon')
++          );
++        }
++      }
++
++      var descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
++
++      if (descriptor && !(descriptor.writable || descriptor.set)) {
++        throw new Error(
++          getErrorMsg(methodName + ' is not declared writable or has no setter')
++        );
++      }
++
++      var originalMethod = obj[methodName],
++        spiedMethod = createSpy(methodName, originalMethod),
++        restoreStrategy;
++
++      if (
++        Object.prototype.hasOwnProperty.call(obj, methodName) ||
++        (obj === global && methodName === 'onerror')
++      ) {
++        restoreStrategy = function() {
++          obj[methodName] = originalMethod;
++        };
++      } else {
++        restoreStrategy = function() {
++          if (!delete obj[methodName]) {
++            obj[methodName] = originalMethod;
++          }
++        };
++      }
++
++      currentSpies().push({
++        restoreObjectToOriginalState: restoreStrategy
++      });
++
++      obj[methodName] = spiedMethod;
++
++      return spiedMethod;
++    };
++
++    this.spyOnProperty = function(obj, propertyName, accessType) {
++      var getErrorMsg = spyOnPropertyMsg;
++
++      accessType = accessType || 'get';
++
++      if (j$.util.isUndefined(obj)) {
++        throw new Error(
++          getErrorMsg(
++            'spyOn could not find an object to spy upon for ' +
++              propertyName +
++              ''
++          )
++        );
++      }
++
++      if (j$.util.isUndefined(propertyName)) {
++        throw new Error(getErrorMsg('No property name supplied'));
++      }
++
++      var descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
++
++      if (!descriptor) {
++        throw new Error(getErrorMsg(propertyName + ' property does not exist'));
++      }
++
++      if (!descriptor.configurable) {
++        throw new Error(
++          getErrorMsg(propertyName + ' is not declared configurable')
++        );
++      }
++
++      if (!descriptor[accessType]) {
++        throw new Error(
++          getErrorMsg(
++            'Property ' +
++              propertyName +
++              ' does not have access type ' +
++              accessType
++          )
++        );
++      }
++
++      if (j$.isSpy(descriptor[accessType])) {
++        if (this.respy) {
++          return descriptor[accessType];
++        } else {
++          throw new Error(
++            getErrorMsg(
++              propertyName + '#' + accessType + ' has already been spied upon'
++            )
++          );
++        }
++      }
++
++      var originalDescriptor = j$.util.clone(descriptor),
++        spy = createSpy(propertyName, descriptor[accessType]),
++        restoreStrategy;
++
++      if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
++        restoreStrategy = function() {
++          Object.defineProperty(obj, propertyName, originalDescriptor);
++        };
++      } else {
++        restoreStrategy = function() {
++          delete obj[propertyName];
++        };
++      }
++
++      currentSpies().push({
++        restoreObjectToOriginalState: restoreStrategy
++      });
++
++      descriptor[accessType] = spy;
++
++      Object.defineProperty(obj, propertyName, descriptor);
++
++      return spy;
++    };
++
++    this.spyOnAllFunctions = function(obj, includeNonEnumerable) {
++      if (j$.util.isUndefined(obj)) {
++        throw new Error(
++          'spyOnAllFunctions could not find an object to spy upon'
++        );
++      }
++
++      var pointer = obj,
++        propsToSpyOn = [],
++        properties,
++        propertiesToSkip = [];
++
++      while (
++        pointer &&
++        (!includeNonEnumerable || pointer !== Object.prototype)
++      ) {
++        properties = getProps(pointer, includeNonEnumerable);
++        properties = properties.filter(function(prop) {
++          return propertiesToSkip.indexOf(prop) === -1;
++        });
++        propertiesToSkip = propertiesToSkip.concat(properties);
++        propsToSpyOn = propsToSpyOn.concat(
++          getSpyableFunctionProps(pointer, properties)
++        );
++        pointer = Object.getPrototypeOf(pointer);
++      }
++
++      for (var i = 0; i < propsToSpyOn.length; i++) {
++        this.spyOn(obj, propsToSpyOn[i]);
++      }
++
++      return obj;
++    };
++
++    this.clearSpies = function() {
++      var spies = currentSpies();
++      for (var i = spies.length - 1; i >= 0; i--) {
++        var spyEntry = spies[i];
++        spyEntry.restoreObjectToOriginalState();
++      }
++    };
++  }
++
++  function getProps(obj, includeNonEnumerable) {
++    var enumerableProperties = Object.keys(obj);
++
++    if (!includeNonEnumerable) {
++      return enumerableProperties;
++    }
++
++    return Object.getOwnPropertyNames(obj).filter(function(prop) {
++      return (
++        prop !== 'constructor' ||
++        enumerableProperties.indexOf('constructor') > -1
++      );
++    });
++  }
++
++  function getSpyableFunctionProps(obj, propertiesToCheck) {
++    var props = [],
++      prop;
++    for (var i = 0; i < propertiesToCheck.length; i++) {
++      prop = propertiesToCheck[i];
++      if (
++        Object.prototype.hasOwnProperty.call(obj, prop) &&
++        isSpyableProp(obj, prop)
++      ) {
++        props.push(prop);
++      }
++    }
++    return props;
++  }
++
++  function isSpyableProp(obj, prop) {
++    var value, descriptor;
++    try {
++      value = obj[prop];
++    } catch (e) {
++      return false;
++    }
++    if (value instanceof Function) {
++      descriptor = Object.getOwnPropertyDescriptor(obj, prop);
++      return (descriptor.writable || descriptor.set) && descriptor.configurable;
++    }
++    return false;
++  }
++
++  return SpyRegistry;
++};
++
++getJasmineRequireObj().SpyStrategy = function(j$) {
++  /**
++   * @interface SpyStrategy
++   */
++  function SpyStrategy(options) {
++    options = options || {};
++
++    var self = this;
++
++    /**
++     * Get the identifying information for the spy.
++     * @name SpyStrategy#identity
++     * @since 3.0.0
++     * @member
++     * @type {String}
++     */
++    this.identity = options.name || 'unknown';
++    this.originalFn = options.fn || function() {};
++    this.getSpy = options.getSpy || function() {};
++    this.plan = this._defaultPlan = function() {};
++
++    var k,
++      cs = options.customStrategies || {};
++    for (k in cs) {
++      if (j$.util.has(cs, k) && !this[k]) {
++        this[k] = createCustomPlan(cs[k]);
++      }
++    }
++
++    var getPromise =
++      typeof options.getPromise === 'function'
++        ? options.getPromise
++        : function() {};
++
++    var requirePromise = function(name) {
++      var Promise = getPromise();
++
++      if (!Promise) {
++        throw new Error(
++          name +
++            ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`'
++        );
++      }
++
++      return Promise;
++    };
++
++    /**
++     * Tell the spy to return a promise resolving to the specified value when invoked.
++     * @name SpyStrategy#resolveTo
++     * @since 3.5.0
++     * @function
++     * @param {*} value The value to return.
++     */
++    this.resolveTo = function(value) {
++      var Promise = requirePromise('resolveTo');
++      self.plan = function() {
++        return Promise.resolve(value);
++      };
++      return self.getSpy();
++    };
++
++    /**
++     * Tell the spy to return a promise rejecting with the specified value when invoked.
++     * @name SpyStrategy#rejectWith
++     * @since 3.5.0
++     * @function
++     * @param {*} value The value to return.
++     */
++    this.rejectWith = function(value) {
++      var Promise = requirePromise('rejectWith');
++
++      self.plan = function() {
++        return Promise.reject(value);
++      };
++      return self.getSpy();
++    };
++  }
++
++  function createCustomPlan(factory) {
++    return function() {
++      var plan = factory.apply(null, arguments);
++
++      if (!j$.isFunction_(plan)) {
++        throw new Error('Spy strategy must return a function');
++      }
++
++      this.plan = plan;
++      return this.getSpy();
++    };
++  }
++
++  /**
++   * Execute the current spy strategy.
++   * @name SpyStrategy#exec
++   * @since 2.0.0
++   * @function
++   */
++  SpyStrategy.prototype.exec = function(context, args, invokeNew) {
++    var contextArgs = [context].concat(
++      args ? Array.prototype.slice.call(args) : []
++    );
++    var target = this.plan.bind.apply(this.plan, contextArgs);
++
++    return invokeNew ? new target() : target();
++  };
++
++  /**
++   * Tell the spy to call through to the real implementation when invoked.
++   * @name SpyStrategy#callThrough
++   * @since 2.0.0
++   * @function
++   */
++  SpyStrategy.prototype.callThrough = function() {
++    this.plan = this.originalFn;
++    return this.getSpy();
++  };
++
++  /**
++   * Tell the spy to return the value when invoked.
++   * @name SpyStrategy#returnValue
++   * @since 2.0.0
++   * @function
++   * @param {*} value The value to return.
++   */
++  SpyStrategy.prototype.returnValue = function(value) {
++    this.plan = function() {
++      return value;
++    };
++    return this.getSpy();
++  };
++
++  /**
++   * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
++   * @name SpyStrategy#returnValues
++   * @since 2.1.0
++   * @function
++   * @param {...*} values - Values to be returned on subsequent calls to the spy.
++   */
++  SpyStrategy.prototype.returnValues = function() {
++    var values = Array.prototype.slice.call(arguments);
++    this.plan = function() {
++      return values.shift();
++    };
++    return this.getSpy();
++  };
++
++  /**
++   * Tell the spy to throw an error when invoked.
++   * @name SpyStrategy#throwError
++   * @since 2.0.0
++   * @function
++   * @param {Error|Object|String} something Thing to throw
++   */
++  SpyStrategy.prototype.throwError = function(something) {
++    var error = j$.isString_(something) ? new Error(something) : something;
++    this.plan = function() {
++      throw error;
++    };
++    return this.getSpy();
++  };
++
++  /**
++   * Tell the spy to call a fake implementation when invoked.
++   * @name SpyStrategy#callFake
++   * @since 2.0.0
++   * @function
++   * @param {Function} fn The function to invoke with the passed parameters.
++   */
++  SpyStrategy.prototype.callFake = function(fn) {
++    if (
++      !(
++        j$.isFunction_(fn) ||
++        j$.isAsyncFunction_(fn) ||
++        j$.isGeneratorFunction_(fn)
++      )
++    ) {
++      throw new Error(
++        'Argument passed to callFake should be a function, got ' + fn
++      );
++    }
++    this.plan = fn;
++    return this.getSpy();
++  };
++
++  /**
++   * Tell the spy to do nothing when invoked. This is the default.
++   * @name SpyStrategy#stub
++   * @since 2.0.0
++   * @function
++   */
++  SpyStrategy.prototype.stub = function(fn) {
++    this.plan = function() {};
++    return this.getSpy();
++  };
++
++  SpyStrategy.prototype.isConfigured = function() {
++    return this.plan !== this._defaultPlan;
++  };
++
++  return SpyStrategy;
++};
++
++getJasmineRequireObj().StackTrace = function(j$) {
++  function StackTrace(error) {
++    var lines = error.stack.split('\n').filter(function(line) {
++      return line !== '';
++    });
++
++    var extractResult = extractMessage(error.message, lines);
++
++    if (extractResult) {
++      this.message = extractResult.message;
++      lines = extractResult.remainder;
++    }
++
++    var parseResult = tryParseFrames(lines);
++    this.frames = parseResult.frames;
++    this.style = parseResult.style;
++  }
++
++  var framePatterns = [
++    // PhantomJS on Linux, Node, Chrome, IE, Edge
++    // e.g. "   at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)"
++    // Note that the "function name" can include a surprisingly large set of
++    // characters, including angle brackets and square brackets.
++    {
++      re: /^\s*at ([^\)]+) \(([^\)]+)\)$/,
++      fnIx: 1,
++      fileLineColIx: 2,
++      style: 'v8'
++    },
++
++    // NodeJS alternate form, often mixed in with the Chrome style
++    // e.g. "  at /some/path:4320:20
++    { re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' },
++
++    // PhantomJS on OS X, Safari, Firefox
++    // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27"
++    // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27"
++    {
++      re: /^(([^@\s]+)@)?([^\s]+)$/,
++      fnIx: 2,
++      fileLineColIx: 3,
++      style: 'webkit'
++    }
++  ];
++
++  // regexes should capture the function name (if any) as group 1
++  // and the file, line, and column as group 2.
++  function tryParseFrames(lines) {
++    var style = null;
++    var frames = lines.map(function(line) {
++      var convertedLine = first(framePatterns, function(pattern) {
++        var overallMatch = line.match(pattern.re),
++          fileLineColMatch;
++        if (!overallMatch) {
++          return null;
++        }
++
++        fileLineColMatch = overallMatch[pattern.fileLineColIx].match(
++          /^(.*):(\d+):\d+$/
++        );
++        if (!fileLineColMatch) {
++          return null;
++        }
++
++        style = style || pattern.style;
++        return {
++          raw: line,
++          file: fileLineColMatch[1],
++          line: parseInt(fileLineColMatch[2], 10),
++          func: overallMatch[pattern.fnIx]
++        };
++      });
++
++      return convertedLine || { raw: line };
++    });
++
++    return {
++      style: style,
++      frames: frames
++    };
++  }
++
++  function first(items, fn) {
++    var i, result;
++
++    for (i = 0; i < items.length; i++) {
++      result = fn(items[i]);
++
++      if (result) {
++        return result;
++      }
++    }
++  }
++
++  function extractMessage(message, stackLines) {
++    var len = messagePrefixLength(message, stackLines);
++
++    if (len > 0) {
++      return {
++        message: stackLines.slice(0, len).join('\n'),
++        remainder: stackLines.slice(len)
++      };
++    }
++  }
++
++  function messagePrefixLength(message, stackLines) {
++    if (!stackLines[0].match(/^\w*Error/)) {
++      return 0;
++    }
++
++    var messageLines = message.split('\n');
++    var i;
++
++    for (i = 1; i < messageLines.length; i++) {
++      if (messageLines[i] !== stackLines[i]) {
++        return 0;
++      }
++    }
++
++    return messageLines.length;
++  }
++
++  return StackTrace;
++};
++
++getJasmineRequireObj().Suite = function(j$) {
++  /**
++   * @interface Suite
++   * @see Env#topSuite
++   * @since 2.0.0
++   */
++  function Suite(attrs) {
++    this.env = attrs.env;
++    /**
++     * The unique ID of this suite.
++     * @name Suite#id
++     * @readonly
++     * @type {string}
++     * @since 2.0.0
++     */
++    this.id = attrs.id;
++    /**
++     * The parent of this suite, or null if this is the top suite.
++     * @name Suite#parentSuite
++     * @readonly
++     * @type {Suite}
++     */
++    this.parentSuite = attrs.parentSuite;
++    /**
++     * The description passed to the {@link describe} that created this suite.
++     * @name Suite#description
++     * @readonly
++     * @type {string}
++     * @since 2.0.0
++     */
++    this.description = attrs.description;
++    this.expectationFactory = attrs.expectationFactory;
++    this.asyncExpectationFactory = attrs.asyncExpectationFactory;
++    this.expectationResultFactory = attrs.expectationResultFactory;
++    this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
++    this.autoCleanClosures =
++      attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
++
++    this.beforeFns = [];
++    this.afterFns = [];
++    this.beforeAllFns = [];
++    this.afterAllFns = [];
++
++    this.timer = attrs.timer || new j$.Timer();
++
++    /**
++     * The suite's children.
++     * @name Suite#children
++     * @type {Array.<(Spec|Suite)>}
++     * @since 2.0.0
++     */
++    this.children = [];
++
++    this.reset();
++  }
++
++  Suite.prototype.setSuiteProperty = function(key, value) {
++    this.result.properties = this.result.properties || {};
++    this.result.properties[key] = value;
++  };
++
++  Suite.prototype.expect = function(actual) {
++    return this.expectationFactory(actual, this);
++  };
++
++  Suite.prototype.expectAsync = function(actual) {
++    return this.asyncExpectationFactory(actual, this);
++  };
++
++  /**
++   * The full description including all ancestors of this suite.
++   * @name Suite#getFullName
++   * @function
++   * @returns {string}
++   * @since 2.0.0
++   */
++  Suite.prototype.getFullName = function() {
++    var fullName = [];
++    for (
++      var parentSuite = this;
++      parentSuite;
++      parentSuite = parentSuite.parentSuite
++    ) {
++      if (parentSuite.parentSuite) {
++        fullName.unshift(parentSuite.description);
++      }
++    }
++    return fullName.join(' ');
++  };
++
++  /*
++   * Mark the suite with "pending" status
++   */
++  Suite.prototype.pend = function() {
++    this.markedPending = true;
++  };
++
++  /*
++   * Like {@link Suite#pend}, but pending state will survive {@link Spec#reset}
++   * Useful for fdescribe, xdescribe, where pending state should remain.
++   */
++  Suite.prototype.exclude = function() {
++    this.pend();
++    this.markedExcluding = true;
++  };
++
++  Suite.prototype.beforeEach = function(fn) {
++    this.beforeFns.unshift(fn);
++  };
++
++  Suite.prototype.beforeAll = function(fn) {
++    this.beforeAllFns.push(fn);
++  };
++
++  Suite.prototype.afterEach = function(fn) {
++    this.afterFns.unshift(fn);
++  };
++
++  Suite.prototype.afterAll = function(fn) {
++    this.afterAllFns.unshift(fn);
++  };
++
++  Suite.prototype.startTimer = function() {
++    this.timer.start();
++  };
++
++  Suite.prototype.endTimer = function() {
++    this.result.duration = this.timer.elapsed();
++  };
++
++  function removeFns(queueableFns) {
++    for (var i = 0; i < queueableFns.length; i++) {
++      queueableFns[i].fn = null;
++    }
++  }
++
++  Suite.prototype.cleanupBeforeAfter = function() {
++    if (this.autoCleanClosures) {
++      removeFns(this.beforeAllFns);
++      removeFns(this.afterAllFns);
++      removeFns(this.beforeFns);
++      removeFns(this.afterFns);
++    }
++  };
++
++  Suite.prototype.reset = function() {
++    /**
++     * @typedef SuiteResult
++     * @property {Int} id - The unique id of this suite.
++     * @property {String} description - The description text passed to the {@link describe} that made this suite.
++     * @property {String} fullName - The full description including all ancestors of this suite.
++     * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
++     * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
++     * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
++     * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
++     * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
++     * @since 2.0.0
++     */
++    this.result = {
++      id: this.id,
++      description: this.description,
++      fullName: this.getFullName(),
++      failedExpectations: [],
++      deprecationWarnings: [],
++      duration: null,
++      properties: null
++    };
++    this.markedPending = this.markedExcluding;
++    this.children.forEach(function(child) {
++      child.reset();
++    });
++  };
++
++  Suite.prototype.addChild = function(child) {
++    this.children.push(child);
++  };
++
++  Suite.prototype.status = function() {
++    if (this.markedPending) {
++      return 'pending';
++    }
++
++    if (this.result.failedExpectations.length > 0) {
++      return 'failed';
++    } else {
++      return 'passed';
++    }
++  };
++
++  Suite.prototype.canBeReentered = function() {
++    return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
++  };
++
++  Suite.prototype.getResult = function() {
++    this.result.status = this.status();
++    return this.result;
++  };
++
++  Suite.prototype.sharedUserContext = function() {
++    if (!this.sharedContext) {
++      this.sharedContext = this.parentSuite
++        ? this.parentSuite.clonedSharedUserContext()
++        : new j$.UserContext();
++    }
++
++    return this.sharedContext;
++  };
++
++  Suite.prototype.clonedSharedUserContext = function() {
++    return j$.UserContext.fromExisting(this.sharedUserContext());
++  };
++
++  Suite.prototype.onException = function() {
++    if (arguments[0] instanceof j$.errors.ExpectationFailed) {
++      return;
++    }
++
++    var data = {
++      matcherName: '',
++      passed: false,
++      expected: '',
++      actual: '',
++      error: arguments[0]
++    };
++    var failedExpectation = this.expectationResultFactory(data);
++
++    if (!this.parentSuite) {
++      failedExpectation.globalErrorType = 'afterAll';
++    }
++
++    this.result.failedExpectations.push(failedExpectation);
++  };
++
++  Suite.prototype.addExpectationResult = function() {
++    if (isFailure(arguments)) {
++      var data = arguments[1];
++      this.result.failedExpectations.push(this.expectationResultFactory(data));
++      if (this.throwOnExpectationFailure) {
++        throw new j$.errors.ExpectationFailed();
++      }
++    }
++  };
++
++  Suite.prototype.addDeprecationWarning = function(deprecation) {
++    if (typeof deprecation === 'string') {
++      deprecation = { message: deprecation };
++    }
++    this.result.deprecationWarnings.push(
++      this.expectationResultFactory(deprecation)
++    );
++  };
++
++  function isFailure(args) {
++    return !args[0];
++  }
++
++  return Suite;
++};
++
++if (typeof window == void 0 && typeof exports == 'object') {
++  /* globals exports */
++  exports.Suite = jasmineRequire.Suite;
++}
++
++getJasmineRequireObj().Timer = function() {
++  var defaultNow = (function(Date) {
++    return function() {
++      return new Date().getTime();
++    };
++  })(Date);
++
++  function Timer(options) {
++    options = options || {};
++
++    var now = options.now || defaultNow,
++      startTime;
++
++    this.start = function() {
++      startTime = now();
++    };
++
++    this.elapsed = function() {
++      return now() - startTime;
++    };
++  }
++
++  return Timer;
++};
++
++getJasmineRequireObj().TreeProcessor = function() {
++  function TreeProcessor(attrs) {
++    var tree = attrs.tree,
++      runnableIds = attrs.runnableIds,
++      queueRunnerFactory = attrs.queueRunnerFactory,
++      nodeStart = attrs.nodeStart || function() {},
++      nodeComplete = attrs.nodeComplete || function() {},
++      failSpecWithNoExpectations = !!attrs.failSpecWithNoExpectations,
++      orderChildren =
++        attrs.orderChildren ||
++        function(node) {
++          return node.children;
++        },
++      excludeNode =
++        attrs.excludeNode ||
++        function(node) {
++          return false;
++        },
++      stats = { valid: true },
++      processed = false,
++      defaultMin = Infinity,
++      defaultMax = 1 - Infinity;
++
++    this.processTree = function() {
++      processNode(tree, true);
++      processed = true;
++      return stats;
++    };
++
++    this.execute = function(done) {
++      if (!processed) {
++        this.processTree();
++      }
++
++      if (!stats.valid) {
++        throw 'invalid order';
++      }
++
++      var childFns = wrapChildren(tree, 0);
++
++      queueRunnerFactory({
++        queueableFns: childFns,
++        userContext: tree.sharedUserContext(),
++        onException: function() {
++          tree.onException.apply(tree, arguments);
++        },
++        onComplete: done
++      });
++    };
++
++    function runnableIndex(id) {
++      for (var i = 0; i < runnableIds.length; i++) {
++        if (runnableIds[i] === id) {
++          return i;
++        }
++      }
++    }
++
++    function processNode(node, parentExcluded) {
++      var executableIndex = runnableIndex(node.id);
++
++      if (executableIndex !== undefined) {
++        parentExcluded = false;
++      }
++
++      if (!node.children) {
++        var excluded = parentExcluded || excludeNode(node);
++        stats[node.id] = {
++          excluded: excluded,
++          willExecute: !excluded && !node.markedPending,
++          segments: [
++            {
++              index: 0,
++              owner: node,
++              nodes: [node],
++              min: startingMin(executableIndex),
++              max: startingMax(executableIndex)
++            }
++          ]
++        };
++      } else {
++        var hasExecutableChild = false;
++
++        var orderedChildren = orderChildren(node);
++
++        for (var i = 0; i < orderedChildren.length; i++) {
++          var child = orderedChildren[i];
++
++          processNode(child, parentExcluded);
++
++          if (!stats.valid) {
++            return;
++          }
++
++          var childStats = stats[child.id];
++
++          hasExecutableChild = hasExecutableChild || childStats.willExecute;
++        }
++
++        stats[node.id] = {
++          excluded: parentExcluded,
++          willExecute: hasExecutableChild
++        };
++
++        segmentChildren(node, orderedChildren, stats[node.id], executableIndex);
++
++        if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
++          stats = { valid: false };
++        }
++      }
++    }
++
++    function startingMin(executableIndex) {
++      return executableIndex === undefined ? defaultMin : executableIndex;
++    }
++
++    function startingMax(executableIndex) {
++      return executableIndex === undefined ? defaultMax : executableIndex;
++    }
++
++    function segmentChildren(
++      node,
++      orderedChildren,
++      nodeStats,
++      executableIndex
++    ) {
++      var currentSegment = {
++          index: 0,
++          owner: node,
++          nodes: [],
++          min: startingMin(executableIndex),
++          max: startingMax(executableIndex)
++        },
++        result = [currentSegment],
++        lastMax = defaultMax,
++        orderedChildSegments = orderChildSegments(orderedChildren);
++
++      function isSegmentBoundary(minIndex) {
++        return (
++          lastMax !== defaultMax &&
++          minIndex !== defaultMin &&
++          lastMax < minIndex - 1
++        );
++      }
++
++      for (var i = 0; i < orderedChildSegments.length; i++) {
++        var childSegment = orderedChildSegments[i],
++          maxIndex = childSegment.max,
++          minIndex = childSegment.min;
++
++        if (isSegmentBoundary(minIndex)) {
++          currentSegment = {
++            index: result.length,
++            owner: node,
++            nodes: [],
++            min: defaultMin,
++            max: defaultMax
++          };
++          result.push(currentSegment);
++        }
++
++        currentSegment.nodes.push(childSegment);
++        currentSegment.min = Math.min(currentSegment.min, minIndex);
++        currentSegment.max = Math.max(currentSegment.max, maxIndex);
++        lastMax = maxIndex;
++      }
++
++      nodeStats.segments = result;
++    }
++
++    function orderChildSegments(children) {
++      var specifiedOrder = [],
++        unspecifiedOrder = [];
++
++      for (var i = 0; i < children.length; i++) {
++        var child = children[i],
++          segments = stats[child.id].segments;
++
++        for (var j = 0; j < segments.length; j++) {
++          var seg = segments[j];
++
++          if (seg.min === defaultMin) {
++            unspecifiedOrder.push(seg);
++          } else {
++            specifiedOrder.push(seg);
++          }
++        }
++      }
++
++      specifiedOrder.sort(function(a, b) {
++        return a.min - b.min;
++      });
++
++      return specifiedOrder.concat(unspecifiedOrder);
++    }
++
++    function executeNode(node, segmentNumber) {
++      if (node.children) {
++        return {
++          fn: function(done) {
++            var onStart = {
++              fn: function(next) {
++                nodeStart(node, next);
++              }
++            };
++
++            queueRunnerFactory({
++              onComplete: function() {
++                var args = Array.prototype.slice.call(arguments, [0]);
++                node.cleanupBeforeAfter();
++                nodeComplete(node, node.getResult(), function() {
++                  done.apply(undefined, args);
++                });
++              },
++              queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
++              userContext: node.sharedUserContext(),
++              onException: function() {
++                node.onException.apply(node, arguments);
++              }
++            });
++          }
++        };
++      } else {
++        return {
++          fn: function(done) {
++            node.execute(
++              done,
++              stats[node.id].excluded,
++              failSpecWithNoExpectations
++            );
++          }
++        };
++      }
++    }
++
++    function wrapChildren(node, segmentNumber) {
++      var result = [],
++        segmentChildren = stats[node.id].segments[segmentNumber].nodes;
++
++      for (var i = 0; i < segmentChildren.length; i++) {
++        result.push(
++          executeNode(segmentChildren[i].owner, segmentChildren[i].index)
++        );
++      }
++
++      if (!stats[node.id].willExecute) {
++        return result;
++      }
++
++      return node.beforeAllFns.concat(result).concat(node.afterAllFns);
++    }
++  }
++
++  return TreeProcessor;
++};
++
++getJasmineRequireObj().UserContext = function(j$) {
++  function UserContext() {}
++
++  UserContext.fromExisting = function(oldContext) {
++    var context = new UserContext();
++
++    for (var prop in oldContext) {
++      if (oldContext.hasOwnProperty(prop)) {
++        context[prop] = oldContext[prop];
++      }
++    }
++
++    return context;
++  };
++
++  return UserContext;
++};
++
++getJasmineRequireObj().version = function() {
++  return '3.10.1';
++};
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c902dc8cbfe22a9690ee2a9361693f50bf7afeb7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++--- jasmine.js.orig   2024-01-20 15:06:20.821078800 +0100
+++++ jasmine.js        2024-01-20 15:07:10.360495593 +0100
++@@ -1,3 +1,4 @@
+++/* jscs:disable */
++ /*
++ Copyright (c) 2008-2021 Pivotal Labs
++ 
++@@ -319,7 +320,7 @@
++   };
++ 
++   j$.isAsymmetricEqualityTester_ = function(obj) {
++-    return obj ? j$.isA_('Function', obj.asymmetricMatch) : false;
+++    return obj?.asymmetricMatch ? j$.isA_('Function', obj.asymmetricMatch) : false;
++   };
++ 
++   j$.getType_ = function(value) {
++@@ -581,7 +582,7 @@
++    * @return {Boolean}
++    */
++   j$.isSpy = function(putativeSpy) {
++-    if (!putativeSpy) {
+++    if (!putativeSpy || !putativeSpy.and) {
++       return false;
++     }
++     return (
++@@ -2249,7 +2250,7 @@
++     };
++ 
++     this.describe = function(description, specDefinitions) {
++-      ensureIsNotNested('describe');
+++      //ensureIsNotNested('describe');
++       ensureIsFunction(specDefinitions, 'describe');
++       var suite = suiteFactory(description);
++       if (specDefinitions.length > 0) {
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7abbbd22103c8ba299e0a6ed1649ec8a33eed5c2
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++# This script is used to build our custom version of the Jasmine library by
++# downloading the upstream file and applying our patches, and is meant for use
++# only when upgrading to a new upstream version.
++curl -o jasmine.js https://raw.githubusercontent.com/jasmine/jasmine/v3.10.1/lib/jasmine-core/jasmine.js
++patch <local-modifications.patch jasmine.js
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f483ac3f9578655735c85e37fb1c0c4ec79738c2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,99 @@@
++project('jasmine-gjs', version: '3.10.1', license: 'MIT',
++    meson_version: '>= 0.58.0')
++
++gjs_dep = dependency('gjs-1.0', required: false)
++if gjs_dep.found()
++    gjs = find_program(gjs_dep.get_variable('gjs_console'))
++else
++    gjs = find_program('gjs', 'gjs-console')
++endif
++
++pkglibexecdir = join_paths(get_option('libexecdir'), meson.project_name())
++pkgdatadir = join_paths(get_option('datadir'), meson.project_name())
++jasmine_mod = meson.project_name()
++
++uninstalled_pkglibexecdir = meson.current_build_dir()
++uninstalled_pkgdatadir = join_paths(meson.current_source_dir(), 'src')
++uninstalled_jasmine_mod = 'lib'
++
++# Executables
++
++config = configuration_data()
++if meson.is_subproject()
++    config.set('pkgdatadir', uninstalled_pkgdatadir)
++    config.set('pkglibexecdir', uninstalled_pkglibexecdir)
++    config.set('jasmine_mod', uninstalled_jasmine_mod)
++else
++    config.set('pkgdatadir', join_paths(get_option('prefix'), pkgdatadir))
++    config.set('pkglibexecdir', join_paths(get_option('prefix'), pkglibexecdir))
++    config.set('jasmine_mod', jasmine_mod)
++endif
++config.set('PACKAGE_VERSION', meson.project_version())
++
++jasmine = configure_file(configuration: config, input: 'bin/jasmine.in',
++    output: 'jasmine', install: not meson.is_subproject(), install_dir: 'bin')
++
++jasmine_runner = configure_file(configuration: config,
++    input: 'bin/jasmine-runner.in', output: 'jasmine-runner',
++    install: not meson.is_subproject(),
++    install_dir: pkglibexecdir)
++
++meson.override_find_program('jasmine', jasmine)
++
++# Source code and Jasmine library
++
++if not meson.is_subproject()
++    install_data(
++        'lib/jasmine.js',
++        'src/command.js',
++        'src/config.js',
++        'src/consoleReporter.js',
++        'src/jasmineBoot.js',
++        'src/junitReporter.js',
++        'src/options.js',
++        'src/tapReporter.js',
++        'src/timer.js',
++        'src/utils.js',
++        'src/verboseReporter.js',
++        'src/xmlWriter.js',
++        install_dir: pkgdatadir,
++    )
++endif
++
++# Documentation
++
++if not meson.is_subproject()
++    install_data('jasmine.man', rename: 'jasmine.1',
++        install_dir: join_paths(get_option('datadir'), 'man', 'man1'))
++endif
++
++# Tests
++
++tests = [
++    'commandSpec',
++    'configSpec',
++    'consoleReporterSpec',
++    'defaultReporterSpec',
++    'focusedSpecIntegrationTest',
++    'importerSpec',
++    'jasmineBootSpec',
++    'jasmineIntegrationTest',
++    'junitReporterSpec',
++    'optionsSpec',
++    'tapReporterSpec',
++    'timerSpec',
++    'utilsSpec',
++    'verboseReporterSpec',
++    'xmlWriterSpec',
++]
++if not meson.is_subproject()
++    test_env = environment()
++    test_env.set('TEST_PKGDATADIR', uninstalled_pkgdatadir)
++    test_env.set('TEST_PKGLIBEXECDIR', uninstalled_pkglibexecdir)
++    test_env.set('TEST_JASMINE_MOD', uninstalled_jasmine_mod)
++    foreach t : tests
++        test_file = files('test/@0@.js'.format(t))
++        test(t, gjs, args: ['-m', jasmine, test_file, '--module', '--tap', '--no-config'],
++            env: test_env, protocol: 'tap')
++    endforeach
++endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c638e642714ef55b68852ba469bfbe27ae0b99b5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,57 @@@
++# Release Checklist #
++
++## Updating to a new upstream release ##
++
++- [ ] Bump version in `meson.build`.
++- [ ] Change upstream Jasmine version in the `lib/update-jasmine.sh` script.
++- [ ] Delete `lib/jasmine.js`.
++- [ ] Run `cd lib; ./update-jasmine.sh` to regenerate `lib/jasmine.js` from the new upstream version.
++- [ ] Resolve patch conflicts with the new upstream version if necessary.
++- [ ] If making a new major release, update `test/jasmineIntegrationTest.js` and `test/focusedSpecIntegrationTest.js` from `https://github.com/jasmine/jasmine.github.io/tree/master/_versions/<VERSION>/src`.
++      Currently we use `introduction.js`, `custom_equality.js`, `custom_matcher.js`, and `focused_specs.js`, but there may be new features that should be included as well.
++      Strip the documentation comments and the weird indentation.
++- [ ] If making a new major release, see if there are any new features that we can use to improve jasmine-gjs's own tests.
++- [ ] Run `meson test`.
++- [ ] Make a commit.
++- [ ] Write release notes in `NEWS.md`.
++
++## Packaging: RPM ##
++
++- [ ] Update the version number in `jasmine-gjs.spec`.
++- [ ] Add a changelog entry in `jasmine-gjs.spec`.
++- [ ] Make any other necessary changes to `jasmine-gjs.spec`.
++- [ ] Run `ninja dist`.
++- [ ] Copy `jasmine-gjs-<VERSION>.tar.xz` to `rpmbuild/SOURCES`.
++- [ ] Copy `jasmine-gjs.spec` to `rpmbuild/SPECS`.
++- [ ] Run `rpmbuild -ba /path/to/rpmbuild/SPECS/jasmine-gjs.spec` to ensure that everything builds OK.
++- [ ] Make a commit.
++
++## Packaging: Debian ##
++
++- [ ] Update the changelog with `dch`. (Distribution = `unstable`)
++- [ ] Make any other necessary changes to the `debian` directory.
++- [ ] Run `debuild -uc -us -b` to ensure that everything builds OK.
++- [ ] Make a commit.
++- [ ] Run `ninja dist`.
++- [ ] Copy `jasmine-gjs-<VERSION>.tar.xz` to `../jasmine-gjs_<VERSION>.orig.tar.xz`.
++- [ ] Extract the tarball.
++- [ ] Enter the directory and run `debuild -uc -us -S` to build a source package.
++
++## Releasing: OBS ##
++
++- [ ] On [OBS](https://build.opensuse.org/project/repositories/home:ptomato), check if repositories should be enabled for any new Fedora, Ubuntu, Debian, or OpenSUSE distribution releases.
++- [ ] Copy `jasmine-gjs-<VERSION>.tar.xz`, `jasmine-gjs.spec`, `jasmine-gjs_<VERSION>.orig.tar.xz`, `jasmine-gjs_<VERSION>-1.debian.tar.xz`, and `jasmine-gjs_<VERSION>-1.dsc` into an OBS checkout of the `home:ptomato/jasmine-gjs` project.
++- [ ] Remove the files in the OBS checkout that are from the previous version.
++- [ ] Run `osc addremove`.
++- [ ] Run `osc commit`.
++- [ ] Check that all builds passed.
++
++## Releasing: Other ##
++
++- [ ] Add `jasmine-gjs-<VERSION>.tar.xz` to the `downloads` directory in the `ptomato/ptomato.github.com` repository.
++- [ ] Modify `opensource/jasmine/jasmine.md` to point to the newest version.
++- [ ] Make a commit.
++- [ ] Back in the `jasmine-gjs` repository, run `git tag <VERSION>`; version is just dotted numbers, e.g. `2.2.1`, no `v` or `Version`.
++- [ ] Push the tag to GitHub.
++- [ ] Copy the release notes from `NEWS.md` into https://github.com/ptomato/jasmine-gjs/releases
++- [ ] Attach the tarball and the sha256sum from the `meson-dist` directory to the release notes.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9f42a018022590a5f31a4ed09a238361a961b08c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,113 @@@
++import Gio from 'gi://Gio';
++import GLib from 'gi://GLib';
++
++import * as Options from './options.js';
++import * as Timer from './timer.js';
++import * as JUnitReporter from './junitReporter.js';
++import * as VerboseReporter from './verboseReporter.js';
++import * as TapReporter from './tapReporter.js';
++import * as ConsoleReporter from './consoleReporter.js';
++
++export const mainloop = GLib.MainLoop.new(null, false);
++
++export async function run(_jasmine, argv, timeout = -1) {
++    const [files, options] = Options.parseOptions(argv);
++
++    if (options.exclude)
++        _jasmine.exclusions = options.exclude;
++
++    if (options.module)
++        _jasmine.module = true;
++
++    if (options.junit) {
++        let junitPath = options.junit;
++        if (!GLib.path_is_absolute(junitPath) &&
++            GLib.getenv('JASMINE_JUNIT_REPORTS_DIR') !== null)
++            junitPath = `${GLib.getenv('JASMINE_JUNIT_REPORTS_DIR')}/${junitPath}`;
++        const junitFile = Gio.File.new_for_commandline_arg(junitPath);
++
++        // Since people might want their report dir structure to mirror
++        // their test dir structure, we shall be kind and try to create any
++        // report directories that don't exist.
++        try {
++            junitFile.get_parent().make_directory_with_parents(null);
++        } catch (e) {
++            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))
++                throw e;
++            // ignore error if directory already exists
++        }
++
++        const rawStream = junitFile.replace(null, false, Gio.FileCreateFlags.NONE, null);
++        const junitStream = new Gio.DataOutputStream({
++            base_stream: rawStream,
++        });
++
++        const junitReporter = new JUnitReporter.JUnitReporter({
++            timerFactory: Timer.createDefaultTimer,
++            print(str) {
++                junitStream.put_string(str, null);
++            },
++        });
++        junitReporter.connect('complete', () => junitStream.close(null));
++        _jasmine.addReporter(junitReporter);
++    }
++
++    let timeoutId;
++    const reporterOptions = {
++        show_colors: options.color,
++        timerFactory: Timer.createDefaultTimer,
++    };
++    let exitCode = 0;
++
++    let reporter;
++    if (options.verbose)
++        reporter = new VerboseReporter.VerboseReporter(reporterOptions);
++    else if (options.tap)
++        reporter = new TapReporter.TapReporter(reporterOptions);
++    else
++        reporter = new ConsoleReporter.DefaultReporter(reporterOptions);
++
++    reporter.connect('started', () => GLib.source_remove(timeoutId));
++    reporter.connect('complete', (_, success) => {
++        if (!success)
++            exitCode = 1;
++        mainloop.quit();
++    });
++    _jasmine.addReporter(reporter);
++
++    // This works around a limitation in GJS 1.40 where exceptions occurring
++    // during module import are swallowed.
++    if (timeout !== -1) {
++        timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, timeout, function () {
++            if (options.tap)
++                print('Bail out! Test suite failed to start within 10 seconds');
++            else
++                printerr('Test suite failed to start within 10 seconds');
++            exitCode = 1;
++            mainloop.quit();
++        });
++    }
++
++    // This should start after the main loop starts, otherwise we will hit
++    // Mainloop.run() only after several tests have already run. For consistency
++    // we should guarantee that there is a main loop running during the tests.
++    GLib.idle_add(GLib.PRIORITY_DEFAULT, function () {
++        _jasmine.execute(files).catch(e => {
++            if (options.tap) {
++                // "Bail out!" has a special meaning to TAP harnesses
++                print('Bail out! Exception occurred inside Jasmine:', e);
++            } else {
++                printerr('Exception occurred inside Jasmine:');
++                printerr(e);
++                printerr(e.stack);
++            }
++            exitCode = 1;
++            mainloop.quit();
++        });
++        return GLib.SOURCE_REMOVE;
++    });
++
++    // _jasmine.execute() queues up all the tests and runs them asynchronously.
++    await mainloop.runAsync();
++    return exitCode;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f2eae16ea8c934ae5ad7699b9e57328faafd0d88
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,142 @@@
++import Gio from 'gi://Gio';
++import GLib from 'gi://GLib';
++
++function _makePathsAbsolute(configFile, paths) {
++    return paths.map(path => {
++        if (GLib.path_is_absolute(path))
++            return path;
++        return configFile.get_parent().resolve_relative_path(path).get_path();
++    });
++}
++
++// Make it legal to specify "some_option": "single_value" in the config file as
++// well as "some_option": ["multiple", "values"]
++export function ensureArray(option) {
++    if (!Array.isArray(option))
++        return [option];
++    return option;
++}
++
++export function loadConfig(options, defaultFile = 'jasmine.json') {
++    if (options['no-config'])
++        return {};
++
++    let config = {};
++    const configFile = Gio.File.new_for_commandline_arg(options.config || defaultFile);
++
++    try {
++        let [, contents] = configFile.load_contents(null);
++        if (contents instanceof Uint8Array)
++            contents = imports.byteArray.toString(contents);
++        config = JSON.parse(contents);
++    } catch (e) {
++        if (!options.config && e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
++            return {};  // Don't complain if config file absent from default location
++        throw new Error(`Configuration not read from ${configFile.get_path()}`);
++    }
++
++    if (config.include_paths) {
++        config.include_paths = _makePathsAbsolute(configFile,
++            ensureArray(config.include_paths));
++    }
++    if (config.spec_files) {
++        config.spec_files = _makePathsAbsolute(configFile,
++            ensureArray(config.spec_files));
++    }
++
++    const RECOGNIZED_KEYS = [
++        'environment',
++        'exclude',
++        'include_paths',
++        'interpreter',
++        'options',
++        'spec_files',
++    ];
++    Object.keys(config).forEach(key => {
++        if (RECOGNIZED_KEYS.indexOf(key) === -1)
++            printerr(`warning: unrecognized config file key "${key}"`);
++    });
++
++    print('Configuration loaded from', configFile.get_path());
++    return config;
++}
++
++function optionsToArgs(options) {
++    const args = [options.color ? '--color' : '--no-color'];
++    if (options.verbose)
++        args.push('--verbose');
++    if (options.module)
++        args.push('--module');
++    if (options.tap)
++        args.push('--tap');
++    if (options.junit) {
++        args.push('--junit');
++        args.push(options.junit);
++    }
++    if (options.exclude) {
++        ensureArray(options.exclude).forEach(exclude => {
++            args.push('--exclude');
++            args.push(exclude);
++        });
++    }
++    return args;
++}
++
++export function configToArgs(config, specFiles = [], options = {}) {
++    let retval = [];
++    if (config.exclude) {
++        ensureArray(config.exclude).forEach(exclude => {
++            retval.push('--exclude');
++            retval.push(exclude);
++        });
++    }
++
++    // Command-line options should always override config file options
++    if (config.options)
++        retval = retval.concat(ensureArray(config.options));
++    retval = retval.concat(optionsToArgs(options), specFiles);
++    // Specific tests given on the command line should always override the
++    // default tests in the config file
++    if (specFiles.length === 0 && config.spec_files)
++        retval = retval.concat(ensureArray(config.spec_files));
++
++    return retval;
++}
++
++export function prepareLauncher(config, options = {}) {
++    let flags = Gio.SubprocessFlags.NONE;
++    if (options.debug)
++        flags |= Gio.SubprocessFlags.STDIN_INHERIT;
++    const launcher = new Gio.SubprocessLauncher({flags});
++    if (config.environment) {
++        Object.keys(config.environment).forEach(key => {
++            if (config.environment[key] === null)
++                launcher.unsetenv(key);
++            else
++                launcher.setenv(key, config.environment[key], true);
++        });
++    }
++    if (config.include_paths) {
++        const existingPaths = launcher.getenv('GJS_PATH');
++        const paths = ensureArray(config.include_paths).slice();
++        if (existingPaths)
++            paths.unshift(existingPaths);
++        launcher.setenv('GJS_PATH', paths.join(':'), /* overwrite = */ true);
++    }
++    return launcher;
++}
++
++export function wrapArgs(args, config, options = {}) {
++    if (options.interpreter)
++        args.unshift(...options.interpreter.split(' '));
++    else if (config.interpreter)
++        args.unshift(...config.interpreter.split(' '));
++    else if (options.module)
++        args.push('--module');
++    if (options.debug) {
++        if (!options.interpreter && !config.interpreter)
++            args.unshift('gjs', '-m');
++        args.unshift(...options.debug.split(' '));
++    }
++    return args;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ac3db00732725b042a3317bc8dd6c66d1df1335e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,254 @@@
++import Gio from 'gi://Gio';
++import GObject from 'gi://GObject';
++
++import {indenter} from './utils.js';
++
++const YELLOW = '\x1b[33m';
++const GREEN = '\x1b[32m';
++const RED = '\x1b[31m';
++const NORMAL = '\x1b[0m';
++
++function createNoopTimer() {
++    return {
++        start() {},
++        elapsed() {
++            return 0;
++        },
++    };
++}
++
++export const ConsoleReporter = GObject.registerClass({
++    Properties: {
++        'show-colors': GObject.ParamSpec.boolean('show-colors', 'Show colors',
++            'Whether to print color output',
++            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
++            true),
++        'jasmine-core-path': GObject.ParamSpec.string('jasmine-core-path',
++            'Jasmine core path',
++            'Path to Jasmine core module for stack trace purposes',
++            GObject.ParamFlags.READWRITE,
++            '/nowhere'),
++    },
++
++    Signals: {
++        'started': {},
++        'complete': {
++            param_types: [GObject.TYPE_BOOLEAN],
++        },
++    },
++}, class ConsoleReporter extends GObject.Object {
++    _init(props = {}) {
++        if (props.hasOwnProperty('print')) {
++            this._print = props.print;
++            delete props.print;
++        }
++
++        this._timerFactory = createNoopTimer;
++        if (props.hasOwnProperty('timerFactory')) {
++            this._timerFactory = props.timerFactory;
++            delete props.timerFactory;
++        }
++
++        super._init(props);
++
++        // The main timer should return 0 if the run hasn't started yet
++        this._timers = {
++            'main': createNoopTimer(),
++        };
++
++        this._failedSpecs = [];
++        this._failedSuites = [];
++        this._suiteLevel = 0;
++        this._specCount = 0;
++        this._passingCount = 0;
++        this._failureCount = 0;
++        this._pendingCount = 0;
++    }
++
++    _color(str, color) {
++        if (typeof color !== 'undefined')
++            return this.show_colors ? color + str + NORMAL : str;
++        return str;
++    }
++
++    // default print function that prints to stdout (GJS' built-in print
++    // functions, print() and printerr(), unfortunately append newlines to
++    // everything)
++    static getStdout() {
++        if (!this._stdout) {
++            const FD_STDOUT = 1;
++            const fdstream = new Gio.UnixOutputStream({
++                fd: FD_STDOUT,
++                close_fd: false,
++            });
++            this._stdout = new Gio.DataOutputStream({
++                base_stream: fdstream,
++            });
++        }
++        return this._stdout;
++    }
++
++    _print(str) {
++        ConsoleReporter.getStdout().put_string(str, null);
++    }
++
++    // Used to start a timer associated with a particular ID. Subclasses can use
++    // this to time actions that the base class doesn't time if they wish.
++    startTimer(id) {
++        this._timers[id] = this._timerFactory(id);
++        this._timers[id].start();
++    }
++
++    // Used to get the elapsed time from a timer with the given ID. Subclasses
++    // can use this to time actions not timed by the base class. The base class
++    // uses timers with the following IDs:
++    //   main - times the whole suite
++    //   suite:foo - times the suite with ID "foo"
++    //   spec:bar - times the spec with ID "bar"
++    elapsedTime(id) {
++        return this._timers[id].elapsed();
++    }
++
++    // Called with an "info" object with the following property:
++    //   totalSpecsDefined - number of specs to be run
++    jasmineStarted() {
++        this.emit('started');
++        this.startTimer('main');
++    }
++
++    jasmineDone() {
++        this.elapsedTime('main');  // Stop the timer
++        this.emit('complete', this._failureCount === 0);
++    }
++
++    // Called with a "result" object with the following properties:
++    //   id - a string unique to this suite
++    //   description - the name of the suite passed to describe()
++    //   fullName - the full name including the names of parent suites
++    //   failedExpectations - a list of failures in this suite
++    suiteStarted(result) {
++        if (result.id)
++            this.startTimer(`suite:${result.id}`);
++        this._suiteLevel++;
++    }
++
++    // Called with the same object as suiteStarted(), with an extra property:
++    //   status - "disabled", "failed", or "finished"
++    // Adds another extra property if the suite was started properly with ID:
++    //   time - time taken to execute the suite, in milliseconds
++    suiteDone(result) {
++        this._suiteLevel--;
++        if (result.failedExpectations && result.failedExpectations.length > 0) {
++            this._failureCount++;
++            this._failedSuites.push(result);
++        }
++        if (result.id)
++            result.time = this.elapsedTime(`suite:${result.id}`);
++    }
++
++    // Called with a "result" object with the following properties:
++    //   id - a string unique to this spec
++    //   description: the name of the spec passed to it()
++    //   fullName - the full name concatenated with the suite's full name
++    //   failedExpectations - a list of failures in this spec
++    //   passedExpectations - a list of succeeded expectations in this spec
++    specStarted(result) {
++        if (result.id)
++            this.startTimer(`spec:${result.id}`);
++        this._specCount++;
++    }
++
++    // Called with the same object as specStarted(), with an extra property:
++    //   status - "disabled", "pending", "failed", or "passed"
++    // Adds another extra property if the spec was started properly with ID:
++    //   time - time taken to execute the spec, in milliseconds
++    specDone(result) {
++        if (result.status === 'passed') {
++            this._passingCount++;
++        } else if (result.status === 'pending') {
++            this._pendingCount++;
++        } else if (result.status === 'failed') {
++            this._failureCount++;
++            this._failedSpecs.push(result);
++        }
++        if (result.id)
++            result.time = this.elapsedTime(`spec:${result.id}`);
++    }
++
++    filterStack(stack) {
++        return stack.split('\n').filter(stackLine => {
++            return stackLine.indexOf(this.jasmine_core_path) === -1;
++        }).join('\n');
++    }
++});
++
++// This reporter has very nearly the same behaviour to Jasmine's default console
++// reporter.
++export const DefaultReporter = GObject.registerClass(class DefaultReporter extends ConsoleReporter {
++    jasmineStarted(info) {
++        super.jasmineStarted(info);
++        this._print('Started\n');
++    }
++
++    jasmineDone() {
++        this._print('\n\n');
++        if (this._failedSpecs.length > 0)
++            this._print('Failures:');
++        this._failedSpecs.forEach(this._printSpecFailureDetails, this);
++
++        if (this._specCount > 0) {
++            this._print('\n');
++            this._print(`${this._specCount} spec${this._specCount === 1 ? '' : 's'}, ${this._failureCount} failed`);
++
++            if (this._pendingCount)
++                this._print(`, ${this._pendingCount} pending`);
++        } else {
++            this._print('No specs found');
++        }
++
++        this._print('\n');
++        const seconds = Math.round(this.elapsedTime('main')) / 1000;
++        this._print(`\nFinished in ${seconds} s\n`);
++
++        this._failedSuites.forEach(this._printSuiteFailureDetails, this);
++
++        super.jasmineDone();
++    }
++
++    specDone(result) {
++        super.specDone(result);
++
++        const colors = {
++            passed: GREEN,
++            pending: YELLOW,
++            failed: RED,
++            disabled: undefined,
++        };
++        const symbols = {
++            passed: '.',
++            pending: '*',
++            failed: 'F',
++            disabled: '',
++        };
++        this._print(this._color(symbols[result.status], colors[result.status]));
++    }
++
++    _printSpecFailureDetails(result, index) {
++        this._print(`\n${index + 1}) ${result.fullName}\n`);
++        result.failedExpectations.forEach(failedExpectation => {
++            const report = `Message:
++${this._color(failedExpectation.message, RED)}
++Stack:
++${this.filterStack(failedExpectation.stack)}
++`;
++            this._print(indenter.indent(report, 2));
++        });
++    }
++
++    _printSuiteFailureDetails(result) {
++        result.failedExpectations.forEach(failedExpectation => {
++            this._print(this._color(`An error was thrown in an afterAll
++AfterAll ${failedExpectation.message}`, RED));
++        });
++    }
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..53e0a3d00c92a9bf94059ab3ac43b3e1717ff4b2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,145 @@@
++/* global jasmineImporter */
++
++import Gio from 'gi://Gio';
++import GLib from 'gi://GLib';
++
++export const Jasmine = class Jasmine {
++    constructor({jasmineCore} = {jasmineCore: jasmineImporter.jasmine}) {
++        const jasmineCorePath = jasmineCore.__file__;
++        this._jasmineCoreFile = Gio.File.new_for_path(jasmineCorePath);
++
++        const jasmineRequire = jasmineCore.getJasmineRequireObj();
++        this._jasmine = jasmineRequire.core(jasmineRequire);
++        this.env = this._jasmine.getEnv();
++        this.env.configure({
++            random: false,
++        });
++        this._jasmineInterface = jasmineRequire.interface(this._jasmine, this.env);
++
++        this.exclusions = [];
++        this.specFiles = [];
++        this.module = false;
++        this._reportersCount = 0;
++    }
++
++    get version() {
++        return this._jasmine.version;
++    }
++
++    addReporter(reporter) {
++        reporter.jasmine_core_path = this._jasmineCoreFile.get_parent().get_path();
++        this.env.addReporter(reporter);
++        this._reportersCount++;
++    }
++
++    _addSpecFile(file) {
++        const absolutePath = file.get_path();
++        const shouldSkip = this.exclusions.some(pattern => {
++            // Match globs against the absolute path
++            if (GLib.pattern_match_simple(pattern, absolutePath))
++                return true;
++            // Also match if the string matches at the end
++            if (GLib.pattern_match_simple(`*/${pattern}`, absolutePath))
++                return true;
++            // Also match if the string matches the path at the end
++            return GLib.pattern_match_simple(`*/${pattern}`,
++                file.get_parent().get_path());
++        });
++        if (shouldSkip)
++            return;
++        if (this.specFiles.indexOf(absolutePath) === -1)
++            this.specFiles.push(absolutePath);
++    }
++
++    addSpecFiles(filePaths) {
++        filePaths.forEach(filePath => {
++            const file = Gio.File.new_for_path(filePath);
++            const type = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);
++
++            switch (type) {
++            case Gio.FileType.REGULAR:
++            case Gio.FileType.UNKNOWN:
++                this._addSpecFile(file);
++                break;
++            case Gio.FileType.DIRECTORY:
++                recurseDirectory(file, this._addSpecFile.bind(this));
++                break;
++            default:
++                // ignore
++            }
++        });
++    }
++
++    async loadSpecs() {
++        await Promise.all(this.specFiles.map(async file => {
++            const oldSearchPath = imports.searchPath.slice();  // make a copy
++            let specImporter = imports['.'];
++
++            const modulePath = GLib.path_get_dirname(file);
++            const moduleName = GLib.path_get_basename(file).slice(0, -3);  // .js
++
++            // Backwards compatibility - let specs import modules from their own
++            // directories
++            imports.searchPath.unshift(modulePath);
++            specImporter.searchPath.unshift(modulePath);
++
++            try {
++                if (this.module)
++                    await import(`file://${file}`);
++                else
++                    await specImporter[moduleName];
++            } catch (err) {
++                if (!(err instanceof SyntaxError || err.name === 'ImportError'))
++                    throw err;
++                // Fake failing suite, to log a failure but continue on with
++                // other specs
++                globalThis.describe(file, function () {
++                    globalThis.it('did not import correctly', function () {
++                        let failureMessage;
++                        if (err instanceof SyntaxError) {
++                            const {fileName, lineNumber, columnNumber, message} = err;
++                            failureMessage = `${fileName}:${lineNumber}:${columnNumber}: ${message}`;
++                        } else {
++                            failureMessage = err.message;
++                        }
++                        globalThis.fail(failureMessage);
++                    });
++                });
++            }
++            imports.searchPath = oldSearchPath;
++
++            // Make a new copy of the importer in case we need to import another
++            // spec with the same filename, so it is not cached
++            specImporter = specImporter['.'];
++        }));
++    }
++
++    async execute(files) {
++        if (files && files.length > 0)
++            this.addSpecFiles(files);
++
++        await this.loadSpecs();
++        this.env.execute();
++    }
++
++    // Install Jasmine API on the global object
++    installAPI(global) {
++        Object.assign(global, this._jasmineInterface);
++    }
++};
++
++function recurseDirectory(directory, func) {
++    const enumerator = directory.enumerate_children('standard::*',
++        Gio.FileQueryInfoFlags.NONE, null);
++
++    let info;
++    while ((info = enumerator.next_file(null))) {
++        const file = enumerator.get_child(info);
++        const filename = file.get_basename();
++
++        if (info.get_file_type() === Gio.FileType.DIRECTORY)
++            recurseDirectory(file, func);
++        else if (filename.endsWith('.js'))
++            func(file);
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3d4a9a677080bbbe55b1bb1d7500c7e127d760f8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,158 @@@
++// Reporter that outputs a JUnit XML test report
++// See http://llg.cubic.org/docs/junit/
++// Unfortunately, the JUnit format is woefully underspecified.
++
++import GLib from 'gi://GLib';
++import GObject from 'gi://GObject';
++
++import {ConsoleReporter} from './consoleReporter.js';
++import * as XMLWriter from './xmlWriter.js';
++
++export const JUnitReporter = GObject.registerClass(class JUnitReporter extends ConsoleReporter {
++    jasmineStarted(info) {
++        this._currentSuite = null;
++        super.jasmineStarted(info);
++        this._tree = new XMLWriter.Node('testsuites');
++        this._suiteCount = 0;
++        this._activeSuites = [];
++
++        const properties = new XMLWriter.Node('properties');
++        properties.children = GLib.listenv().map(key => {
++            const property = new XMLWriter.Node('property');
++            property.attrs = {
++                name: key,
++                value: GLib.getenv(key),
++            };
++            return property;
++        });
++        this._tree.children.push(properties);
++    }
++
++    jasmineDone() {
++        const failedAfterAlls = this._failedSuites.length;
++        if (failedAfterAlls > 0) {
++            const afterAllSuite = new XMLWriter.Node('testsuite');
++            afterAllSuite.attrs = {
++                name: 'afterAll()',
++                tests: failedAfterAlls,
++                errors: failedAfterAlls,
++                id: this._suiteCount++,
++            };
++            afterAllSuite.children = this._failedSuites.map(failure => {
++                const afterAllCase = new XMLWriter.Node('testcase');
++                afterAllCase.attrs = {
++                    name: failure.description,
++                    classname: 'AfterAll',
++                    assertions: failure.failedExpectations.length,
++                };
++                afterAllCase.children = failure.failedExpectations.map(result => {
++                    const error = new XMLWriter.Node('error');
++                    error.attrs = _parseExceptionMessage(result);
++                    error.text = result.stack;
++                    return error;
++                });
++                return afterAllCase;
++            });
++            this._tree.children.push(afterAllSuite);
++        }
++
++        // Timer inherited from ConsoleReporter
++        this._tree.attrs = {
++            time: this.elapsedTime('main') / 1000,
++        };
++
++        this._print(this._tree.toString());
++
++        super.jasmineDone();
++    }
++
++    // Jenkins parses nested JUnit test suites but doesn't display them properly.
++    // See https://issues.jenkins-ci.org/browse/JENKINS-18673
++    // Therefore, we flatten all suites into one level.
++    suiteStarted(result) {
++        super.suiteStarted(result);
++        this._activeSuites.push(this._currentSuite);
++        this._currentSuite = new XMLWriter.Node('testsuite');
++        this._currentSuite.attrs = {
++            name: result.fullName,
++            id: this._suiteCount++,
++            tests: 0,
++            disabled: 0,
++            failures: 0,
++            errors: 0,
++            skipped: 0,
++            timestamp: GLib.DateTime.new_now_local().format('%Y-%m-%dT%H:%M:%S'),
++        };
++        this._tree.children.push(this._currentSuite);
++    }
++
++    suiteDone(result) {
++        super.suiteDone(result);
++        this._currentSuite.attrs.time = result.time / 1000;  // in seconds
++        this._currentSuite = this._activeSuites.pop();
++    }
++
++    specStarted(result) {
++        super.specStarted(result);
++        this._currentSuite.attrs.tests++;
++    }
++
++    specDone(result) {
++        super.specDone(result);
++
++        const spec = new XMLWriter.Node('testcase');
++        spec.attrs = {
++            name: result.description,
++            classname: this._currentSuite.attrs['name'],
++            assertions: result.failedExpectations.length +
++                result.passedExpectations.length,
++            time: result.time / 1000,  // in seconds
++        };
++
++        switch (result.status) {
++        case 'disabled':
++            this._currentSuite.attrs.disabled++;
++            return;
++        case 'failed': {
++            // We count a failure as a "failure" if at least one expectation
++            // failed. If there were only uncaught exceptions, then it is an
++            // "error".
++            let assertFailed = false;
++            result.failedExpectations.forEach(failedExpectation => {
++                let node;
++                if (failedExpectation.matcherName !== '') {
++                    assertFailed = true;
++                    node = new XMLWriter.Node('failure');
++                    node.attrs = {
++                        type: failedExpectation.matcherName,
++                        message: failedExpectation.message,
++                    };
++                } else {
++                    node = new XMLWriter.Node('error');
++                    node.attrs = _parseExceptionMessage(failedExpectation);
++                }
++                node.text = this.filterStack(failedExpectation.stack);
++                spec.children.push(node);
++            });
++            if (assertFailed)
++                this._currentSuite.attrs.failures++;
++            else
++                this._currentSuite.attrs.errors++;
++        }
++            break;
++        case 'pending':
++            this._currentSuite.attrs.skipped++;
++            spec.children.push(new XMLWriter.Node('skipped'));
++            break;
++        }
++        this._currentSuite.children.push(spec);
++    }
++});
++
++function _parseExceptionMessage(expectation) {
++    const parse = expectation.message.split(':');
++    return {
++        type: parse.length > 1 ? parse[0] : 'Error',
++        message: expectation.message,
++    };
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..25d3b25bd4e1ed9abd04f8937fc064f047ed54e8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,150 @@@
++import * as System from 'system';
++
++const ARGS = {
++    'help': {
++        help: 'show this help',
++        action: 'help',
++    },
++    'version': {
++        help: 'print program version',
++        action: 'store_true',
++    },
++    'no-color': {
++        help: 'turn off color in spec output',
++        dest: 'color',
++        action: 'store_false',
++        default: true,
++    },
++    'color': {
++        help: 'turn on color in spec output',
++        action: 'store_true',
++    },
++    'verbose': {
++        help: 'print verbose results (similar to mocha)',
++        action: 'store_true',
++    },
++    'tap': {
++        help: 'output results in TAP format',
++        action: 'store_true',
++    },
++    'junit': {
++        help: 'output a JUnit report to the given file [report.xml]',
++        action: 'store',
++        nargs: '?',
++        const: 'report.xml',
++    },
++    'config': {
++        help: 'load configuration from the given file',
++        action: 'store',
++    },
++    'no-config': {
++        help: 'ignore the default jasmine.json config file',
++        action: 'store_true',
++    },
++    'exclude': {
++        help: 'do not execute the given spec (may include wildcards)',
++        action: 'append',
++    },
++    'module': {
++        help: 'execute specs as module',
++        action: 'store_true',
++    },
++    'interpreter': {
++        help: 'run with the given program instead of /usr/bin/env gjs',
++        action: 'store',
++    },
++    'debug': {
++        help: 'run with a debugger [gdb --args]',
++        action: 'store',
++        nargs: '?',
++        const: 'gdb --args',
++    },
++};
++
++export function parseOptions(argv) {
++    argv = argv.slice();  // Make a copy
++    const namespace = {};
++    const files = [];
++
++    Object.keys(ARGS).forEach(function (argName) {
++        const argInfo = ARGS[argName];
++        const dest = argInfo.dest || argName;
++        if (typeof argInfo.default !== 'undefined')
++            namespace[dest] = argInfo.default;
++    });
++
++    let argvElement;
++    while ((argvElement = argv.shift())) {
++        if (!argvElement.startsWith('-')) {
++            files.push(argvElement);
++            continue;
++        }
++
++        if (!argvElement.startsWith('--')) {
++            printerr(`warning: Unknown argument "${argvElement}"`);
++            continue;
++        }
++        const argName = argvElement.slice(2);
++        if (!(argName in ARGS)) {
++            printerr(`warning: Unknown argument "${argvElement}"`);
++            continue;
++        }
++
++        const argInfo = ARGS[argName];
++        const dest = argInfo.dest || argName;
++        let value;
++        switch (argInfo.action) {
++        case 'help':
++            help();
++            break;
++        case 'store_true':
++            namespace[dest] = true;
++            break;
++        case 'store_false':
++            namespace[dest] = false;
++            break;
++        case 'store':
++            value = _getNextArgument(argv);
++            if (typeof value === 'undefined' && argInfo.nargs === '?')
++                value = argInfo.const;
++            if (typeof value === 'undefined') {
++                printerr(`warning: Missing value for argument "${argName}"`);
++                continue;
++            }
++            namespace[dest] = value;
++            break;
++        case 'append':
++            value = _getNextArgument(argv);
++            if (typeof value === 'undefined') {
++                printerr(`warning: Missing value for argument "${argName}"`);
++                continue;
++            }
++            if (!(dest in namespace))
++                namespace[dest] = [];
++            namespace[dest].push(value);
++            break;
++        }
++    }
++    return [files, namespace];
++}
++
++function _getNextArgument(argv) {
++    let value = argv.shift();
++    if (typeof value !== 'undefined' && value.startsWith('--')) {
++        argv.unshift(value);
++        value = undefined;
++    }
++    return value;
++}
++
++function help() {
++    print('Usage: jasmine [-I <include path>] [options] <files or directories>\n');
++    print('If file given, runs the spec in that file. If directory given,');
++    print('searches for and runs specs under that directory.\n');
++    print('Options:');
++    Object.keys(ARGS).forEach(function (argName) {
++        print(`${`--${argName}`.padStart(15)}\t\t${ARGS[argName].help}`);
++    });
++    print('');
++    System.exit(0);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..08746cd779c0d02973f350e3dafeb42112809ff0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,72 @@@
++// Reporter that outputs according to the Test Anything Protocol
++// See http://testanything.org/tap-specification.html
++
++import GObject from 'gi://GObject';
++
++import {ConsoleReporter} from './consoleReporter.js';
++
++export const TapReporter = GObject.registerClass(class TapReporter extends ConsoleReporter {
++    jasmineStarted(info) {
++        super.jasmineStarted(info);
++        this._print(`1..${info.totalSpecsDefined}\n`);
++    }
++
++    jasmineDone() {
++        this._failedSuites.forEach(failure => {
++            failure.failedExpectations.forEach(result => {
++                this._print(`not ok - An error was thrown in an afterAll(): ${result.message}\n`);
++            });
++        });
++        super.jasmineDone();
++    }
++
++    suiteStarted(result) {
++        super.suiteStarted(result);
++        this._print(`# Suite started: ${result.fullName}\n`);
++    }
++
++    suiteDone(result) {
++        super.suiteDone(result);
++        if (result.status === 'disabled') {
++            this._print(`# Suite was disabled: ${result.fullName}\n`);
++        } else {
++            const failures = result.failedExpectations.length;
++            this._print(`# Suite finished with ${failures} failure${failures === 1 ? '' : 's'}: ${result.fullName}\n`);
++        }
++    }
++
++    specDone(result) {
++        super.specDone(result);
++
++        if (result.status === 'failed')
++            this._print('not ok');
++        else
++            this._print('ok');
++        this._print(` ${this._specCount} - ${result.fullName}`);
++        if (result.status === 'pending' || result.status === 'disabled') {
++            const reason = result.pendingReason || result.status;
++            this._print(` # SKIP ${reason}`);
++        }
++        if (result.status === 'failed' && result.failedExpectations) {
++            const messages = result.failedExpectations.map(r => _removeNewlines(r.message)).join(' ');
++            this._print(` (${messages})`);
++        }
++        this._print('\n');
++
++        // Print additional diagnostic info on failure
++        if (result.status === 'failed' && result.failedExpectations) {
++            result.failedExpectations.forEach(failedExpectation => {
++                this._print(`# Message: ${_removeNewlines(failedExpectation.message)}\n`);
++                this._print('# Stack:\n');
++                const stackTrace = this.filterStack(failedExpectation.stack).trim();
++                this._print(stackTrace.split('\n').map(str => `#   ${str}`).join('\n'));
++                this._print('\n');
++            });
++        }
++    }
++});
++
++function _removeNewlines(str) {
++    const allNewlines = /\n/g;
++    return str.replace(allNewlines, '\\n');
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6a5b7886411494d58f27548e375e44ad30d74ec7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++import GLib from 'gi://GLib';
++
++// Measures elapsed time in milliseconds.
++export function createDefaultTimer() {
++    let startTime, elapsedTime;
++    return {
++        start() {
++            startTime = GLib.get_monotonic_time();
++        },
++        elapsed() {
++            if (!elapsedTime)
++                elapsedTime = (GLib.get_monotonic_time() - startTime) / 1000;
++            return elapsedTime;
++        },
++    };
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..aee690532cad6ff63d40a4602f656af4a5fe88d8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++export const indenter = {
++    indent(str, spaces) {
++        return str.split('\n').map(line => {
++            if (line === '')
++                return line;
++            return ' '.repeat(spaces) + line;
++        }).join('\n');
++    },
++};
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c5a7ead801ebfaf699e662bd599892468f1cfc8d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,100 @@@
++import GObject from 'gi://GObject';
++
++import {ConsoleReporter} from './consoleReporter.js';
++import {indenter} from './utils.js';
++
++const GRAY = '\x1b[38;5;246m';
++const YELLOW = '\x1b[33m';
++const GREEN = '\x1b[32m';
++const RED = '\x1b[31m';
++
++// This reporter, activated with --verbose on the command line, behaves very
++// similarly to Mocha's nicely formatted reporter.
++export const VerboseReporter = GObject.registerClass(class VerboseReporter extends ConsoleReporter {
++    jasmineStarted(info) {
++        super.jasmineStarted(info);
++        this._print('Started\n\n');
++    }
++
++    jasmineDone() {
++        this._print('\n');
++        this._failedSpecs.forEach(this._printSpecFailureDetails, this);
++        const seconds = Math.round(this.elapsedTime('main')) / 1000;
++
++        this._print(this._color(`  ${this._passingCount} passing`, GREEN));
++        this._print(` (${seconds} s)\n`);
++        if (this._pendingCount > 0)
++            this._print(this._color(`  ${this._pendingCount} pending\n`, YELLOW));
++        if (this._failureCount > 0)
++            this._print(this._color(`  ${this._failureCount} failing\n`, RED));
++        this._print('\n');
++
++        this._failedSuites.forEach(this._printSuiteFailureDetails, this);
++
++        super.jasmineDone();
++    }
++
++    suiteStarted(result) {
++        super.suiteStarted(result);
++        this._print(indenter.indent(this._color(result.description, GRAY),
++            this._suiteLevel * 2));
++        this._print('\n');
++    }
++
++    suiteDone(result) {
++        if (result.status === 'disabled') {
++            this._print(indenter.indent(`${this._color('(disabled)', YELLOW)}\n`,
++                this._suiteLevel * 2 + 2));
++        }
++
++        super.suiteDone(result);
++
++        if (this._suiteLevel === 0)
++            this._print('\n');
++    }
++
++    specDone(result) {
++        super.specDone(result);
++
++        const colors = {
++            passed: GREEN,
++            pending: YELLOW,
++            failed: RED,
++            disabled: undefined,
++        };
++        const symbols = {
++            passed: '✓',
++            pending: '-',
++            failed: `${this._failureCount})`,
++            disabled: 'x',
++        };
++        this._print(indenter.indent(this._color(symbols[result.status],
++            colors[result.status]), this._suiteLevel * 2 + 2));
++        this._print(` ${result.description}`);
++        if (result.time > 75)
++            this._print(` ${this._color(`(${result.time} ms)`, RED)}`);
++        else if (result.time > 40)
++            this._print(` ${this._color(`(${result.time} ms)`, YELLOW)}`);
++        if (result.pendingReason)
++            this._print(` ${this._color(`(${result.pendingReason})`, YELLOW)}`);
++        this._print('\n');
++    }
++
++    _printSpecFailureDetails(result, index) {
++        this._print(this._color(`${index + 1}) ${result.fullName}\n\n`, RED));
++
++        result.failedExpectations.forEach(failedExpectation => {
++            this._print(indenter.indent(this._color(failedExpectation.message, GRAY), 2));
++            this._print('\n');
++            this._print(indenter.indent(this.filterStack(failedExpectation.stack), 4));
++            this._print('\n\n');
++        });
++    }
++
++    _printSuiteFailureDetails(result) {
++        result.failedExpectations.forEach(failedExpectation => {
++            this._print(this._color(`An error was thrown in an afterAll
++AfterAll ${failedExpectation.message}`, RED));
++        });
++    }
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cce33a71fe1d5aedda7a0614af319ea3472d8157
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,38 @@@
++import GLib from 'gi://GLib';
++
++import {indenter} from './utils.js';
++
++export const Node = class Node {
++    constructor(name) {
++        this.name = name;
++        this.attrs = {};
++        this.children = [];
++        this.text = '';
++    }
++
++    toString() {
++        return `<?xml version="1.0" encoding="UTF-8"?>\n${_prettyprint(this)}`;
++    }
++};
++
++function _attrsToString(attrs) {
++    return Object.keys(attrs).map(key => {
++        const value = attrs[key].toString();
++        return ` ${key}="${GLib.markup_escape_text(value, -1)}"`;
++    }).join('');
++}
++
++function _prettyprint(node) {
++    if (node.children.length === 0 && node.text.length === 0)
++        return `<${node.name}${_attrsToString(node.attrs)}/>\n`;
++
++    const elementTop = `<${node.name}${_attrsToString(node.attrs)}>\n`;
++    const elementBottom = `</${node.name}>\n`;
++    const children = node.children.map(_prettyprint).join('');
++    let text = GLib.markup_escape_text(node.text, -1).trim();
++    if (text.length !== 0)
++        text += '\n';
++
++    return elementTop + indenter.indent(children, 2) + indenter.indent(text, 2) +
++        elementBottom;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..14b7a033a8d2654fbe8bef8b6b079bde5bb0354c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,29 @@@
++---
++env:
++  jasmine: true
++rules:
++  no-restricted-globals:
++    - error
++    - name: fdescribe
++      message: Do not commit fdescribe(). Use describe() instead.
++    - name: fit
++      message: Do not commit fit(). Use it() instead.
++  no-restricted-syntax:
++    - error
++    - selector: CallExpression[callee.name="it"] > ArrowFunctionExpression
++      message: Arrow functions can mess up some Jasmine APIs. Use function () instead
++    - selector: CallExpression[callee.name="describe"] > ArrowFunctionExpression
++      message: Arrow functions can mess up some Jasmine APIs. Use function () instead
++    - selector: CallExpression[callee.name="beforeEach"] > ArrowFunctionExpression
++      message: Arrow functions can mess up some Jasmine APIs. Use function () instead
++    - selector: CallExpression[callee.name="afterEach"] > ArrowFunctionExpression
++      message: Arrow functions can mess up some Jasmine APIs. Use function () instead
++    - selector: CallExpression[callee.name="beforeAll"] > ArrowFunctionExpression
++      message: Arrow functions can mess up some Jasmine APIs. Use function () instead
++    - selector: CallExpression[callee.name="afterAll"] > ArrowFunctionExpression
++      message: Arrow functions can mess up some Jasmine APIs. Use function () instead
++globals:
++  clearInterval: writable
++  clearTimeout: writable
++  setInterval: writable
++  setTimeout: writable
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3456d7d30125eab0c64dc6e44f6b73e0648e3163
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,124 @@@
++import Gio from 'gi://Gio';
++import GLib from 'gi://GLib';
++
++import * as Command from '../src/command.js';
++import * as JUnitReporter from '../src/junitReporter.js';
++import * as TapReporter from '../src/tapReporter.js';
++import * as VerboseReporter from '../src/verboseReporter.js';
++
++const {mainloop} = Command;
++
++describe('Jasmine command', function () {
++    let fakeJasmine;
++
++    beforeAll(function () {
++        Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish');
++    });
++
++    beforeEach(function () {
++        fakeJasmine = jasmine.createSpyObj('jasmine', ['addReporter', 'configureDefaultReporter', 'execute']);
++        spyOn(mainloop, 'runAsync');  // stub out system behaviour
++    });
++
++    describe('running specs', function () {
++        it('shows colors by default', function () {
++            Command.run(fakeJasmine, []);
++            expect(fakeJasmine.addReporter)
++                .toHaveBeenCalledWith(jasmine.objectContaining({show_colors: true}));
++        });
++
++        it('allows colors to be turned off', function () {
++            Command.run(fakeJasmine, ['--no-color']);
++            expect(fakeJasmine.addReporter)
++                .toHaveBeenCalledWith(jasmine.objectContaining({show_colors: false}));
++        });
++
++        it('lets later color arguments override earlier ones', function () {
++            Command.run(fakeJasmine, ['--color', '--no-color']);
++            expect(fakeJasmine.addReporter)
++                .toHaveBeenCalledWith(jasmine.objectContaining({show_colors: false}));
++            Command.run(fakeJasmine, ['--no-color', '--color']);
++            expect(fakeJasmine.addReporter)
++                .toHaveBeenCalledWith(jasmine.objectContaining({show_colors: true}));
++        });
++
++        it('loads the verbose reporter', function () {
++            Command.run(fakeJasmine, ['--verbose']);
++            expect(fakeJasmine.addReporter).toHaveBeenCalled();
++            const [reporter] = fakeJasmine.addReporter.calls.argsFor(0);
++            expect(reporter.constructor).toBe(VerboseReporter.VerboseReporter);
++        });
++
++        it('loads the TAP reporter', function () {
++            Command.run(fakeJasmine, ['--tap']);
++            expect(fakeJasmine.addReporter).toHaveBeenCalled();
++            const [reporter] = fakeJasmine.addReporter.calls.argsFor(0);
++            expect(reporter.constructor).toBe(TapReporter.TapReporter);
++        });
++
++        it('loads the JUnit reporter alongside the usual reporter', function () {
++            // Unfortunately /dev/null can't be opened as a GFile, so we need to
++            // write to a temporary file.
++            const [tmpFile, stream] = Gio.File.new_tmp('junitreportXXXXXX');
++            const tmpPath = tmpFile.get_path();
++            stream.close(null);
++
++            Command.run(fakeJasmine, ['--junit', tmpPath]);
++            expect(fakeJasmine.addReporter.calls.count()).toBe(2);
++            const reporters = fakeJasmine.addReporter.calls.allArgs().map(args => args[0].constructor);
++            expect(reporters).toContain(JUnitReporter.JUnitReporter);
++
++            tmpFile.delete_async(GLib.PRIORITY_DEFAULT, null).then(() => {});
++        });
++
++        it('creates a directory for the report if necessary', function () {
++            const tmpDir = GLib.dir_make_tmp('junitreportXXXXXX');
++            const tmpFile =
++                Gio.File.new_for_path(tmpDir).get_child('dir').get_child('report.xml');
++            const tmpPath = tmpFile.get_path();
++
++            Command.run(fakeJasmine, ['--junit', tmpPath]);
++            expect(tmpFile.query_exists(null)).toBeTruthy();
++
++            tmpFile.delete_async(GLib.PRIORITY_DEFAULT, null)
++                .then(() => tmpFile.get_parent().delete_async(GLib.PRIORITY_DEFAULT, null))
++                .then(() => tmpFile.get_parent().get_parent().delete_async(GLib.PRIORITY_DEFAULT, null));
++        });
++
++        it('uses the value of JASMINE_JUNIT_REPORTS_DIR', function () {
++            const oldPath = GLib.getenv('JASMINE_JUNIT_REPORTS_DIR');
++            const tmpDir = GLib.dir_make_tmp('junitreportXXXXXX');
++            GLib.setenv('JASMINE_JUNIT_REPORTS_DIR', tmpDir, true);
++
++            Command.run(fakeJasmine, ['--junit', 'report.xml']);
++            const reportFile =
++                Gio.File.new_for_path(tmpDir).get_child('report.xml');
++            expect(reportFile.query_exists(null)).toBeTruthy();
++
++            reportFile.delete_async(GLib.PRIORITY_DEFAULT, null)
++                .then(() => reportFile.get_parent().delete_async(GLib.PRIORITY_DEFAULT, null));
++
++            if (oldPath !== null)
++                GLib.setenv('JASMINE_JUNIT_REPORTS_DIR', oldPath, true);
++            else
++                GLib.unsetenv('JASMINE_JUNIT_REPORTS_DIR');
++        });
++
++        it('executes the Jasmine suite', function (done) {
++            expectAsync(Command.run(fakeJasmine, [])).toBeResolvedTo(0);
++            // fakeJasmine.execute() is started in idle
++            GLib.idle_add(GLib.PRIORITY_DEFAULT, function () {
++                expect(fakeJasmine.execute).toHaveBeenCalled();
++                done();
++            });
++        });
++
++        it('runs the specified specs', function (done) {
++            Command.run(fakeJasmine, ['spec/some/fileSpec.js', '--no-color']);
++            GLib.idle_add(GLib.PRIORITY_DEFAULT, function () {
++                expect(fakeJasmine.execute).toHaveBeenCalledWith(['spec/some/fileSpec.js']);
++                done();
++            });
++        });
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4edbf75a398f238042853cd8bca6af515d05e8a9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,270 @@@
++import Gio from 'gi://Gio';
++import GLib from 'gi://GLib';
++
++import * as Config from '../src/config.js';
++import * as Options from '../src/options.js';
++
++const [testFile] = GLib.filename_from_uri(import.meta.url);
++const testDir = GLib.path_get_dirname(testFile);
++
++describe('Ensure array', function () {
++    it('does not change an array', function () {
++        expect(Config.ensureArray(['a', 'b'])).toEqual(['a', 'b']);
++    });
++
++    it('puts a single value into an array', function () {
++        expect(Config.ensureArray('a')).toEqual(['a']);
++    });
++});
++
++describe('Loading configuration', function () {
++    beforeEach(function () {
++        // suppress messages
++        spyOn(globalThis, 'print');
++        spyOn(globalThis, 'printerr');
++    });
++
++    it('loads from a file', function () {
++        const config = Config.loadConfig({config: `${testDir}/fixtures/jasmine.json`});
++        expect(config.a).toEqual('b');
++        expect(config.c).toEqual('d');
++    });
++
++    it("doesn't load the file if no-config specified", function () {
++        const config = Config.loadConfig({
++            'no-config': true,
++            config: `${testDir}/fixtures/jasmine.json`,
++        });
++        const keys = Object.keys(config);
++        expect(keys).not.toContain('a');
++        expect(keys).not.toContain('c');
++    });
++
++    it('loads the default file if none given', function () {
++        const config = Config.loadConfig({}, `${testDir}/fixtures/jasmine.json`);
++        expect(config.a).toEqual('b');
++        expect(config.c).toEqual('d');
++    });
++
++    it("errors out if the file doesn't exist", function () {
++        expect(() => Config.loadConfig({config: 'nonexist.json'})).toThrow();
++    });
++
++    it("doesn't error out if the default file doesn't exist", function () {
++        expect(() => Config.loadConfig({}, 'nonexist.json')).not.toThrow();
++    });
++
++    it('errors out if the file is invalid', function () {
++        expect(() => Config.loadConfig({
++            config: `${testDir}/fixtures/invalid.json`,
++        })).toThrow();
++    });
++
++    it("resolves paths relative to the config file's location", function () {
++        const config = Config.loadConfig({config: `${testDir}/fixtures/path.json`});
++        const location = Gio.File.new_for_path(`${testDir}/fixtures`);
++
++        expect(config.include_paths).toContain(location.get_path());
++        expect(config.spec_files).toContain(location.get_child('someSpec.js').get_path());
++    });
++
++    it('warns about unrecognized config options', function () {
++        Config.loadConfig({config: `${testDir}/fixtures/jasmine.json`});
++        expect(globalThis.printerr).toHaveBeenCalledWith(jasmine.stringMatching(/^warning: /));
++    });
++});
++
++describe('Configuration options to arguments', function () {
++    it('lets command line arguments override config options', function () {
++        const args = Config.configToArgs({options: '--color'},
++            ...Options.parseOptions(['--no-color']));
++        expect(args.indexOf('--no-color')).toBeGreaterThan(args.indexOf('--color'));
++    });
++
++    it('adds one exclusion path', function () {
++        const args = Config.configToArgs({exclude: 'a'});
++        expect(args.join(' ')).toMatch('--exclude a');
++    });
++
++    it('adds more than one exclusion path', function () {
++        const args = Config.configToArgs({exclude: ['a', 'b']});
++        expect(args.join(' ')).toMatch('--exclude a');
++        expect(args.join(' ')).toMatch('--exclude b');
++    });
++
++    it('adds exclusions from the command line', function () {
++        const args = Config.configToArgs({}, ...Options.parseOptions(['--exclude', 'a.js']));
++        expect(args.join(' ')).toMatch('--exclude a.js');
++    });
++
++    it('combines exclusions from the command line and the config file', function () {
++        const args = Config.configToArgs({exclude: 'b.js'},
++            ...Options.parseOptions(['--exclude', 'a.js']));
++        expect(args.join(' ')).toMatch('--exclude a.js');
++        expect(args.join(' ')).toMatch('--exclude b.js');
++    });
++
++    it('adds one extra option', function () {
++        const args = Config.configToArgs({options: '--foo'});
++        expect(args).toContain('--foo');
++    });
++
++    it('adds more than one extra option', function () {
++        const args = Config.configToArgs({options: ['--foo', '--bar']});
++        expect(args.join(' ')).toMatch('--foo --bar');
++        // order should be preserved here
++    });
++
++    it('adds one spec file', function () {
++        const args = Config.configToArgs({spec_files: 'a'});
++        expect(args).toContain('a');
++    });
++
++    it('adds more than one spec file', function () {
++        const args = Config.configToArgs({spec_files: ['a', 'b']});
++        expect(args).toContain('a');
++        expect(args).toContain('b');
++    });
++
++    it('does not add spec files from config if there were some on the command line', function () {
++        const args = Config.configToArgs({spec_files: ['a', 'b']}, ['c']);
++        expect(args).not.toContain('a');
++        expect(args).not.toContain('b');
++    });
++
++    it('passes the arguments on to the subprocess', function () {
++        const args = Config.configToArgs({}, ...Options.parseOptions(['--color', 'spec.js']));
++        expect(args).toContain('--color', 'spec.js');
++    });
++
++    it('passes the config file on to the subprocess as arguments', function () {
++        const args = Config.configToArgs({
++            environment: {},
++            options: ['--color'],
++            exclude: ['nonspec*.js'],
++            spec_files: ['a.js', 'b.js'],
++        }, [], {});
++        expect(args.join(' ')).toMatch(/--exclude nonspec\*\.js/);
++        expect(args).toContain('--color', 'a.js', 'b.js');
++    });
++
++    it('does not pass the config file specs if specs were on the command line', function () {
++        const args = Config.configToArgs({
++            environment: {},
++            spec_files: ['spec2.js'],
++        }, ['spec1.js']);
++        expect(args).toContain('spec1.js');
++        expect(args).not.toContain('spec2.js');
++    });
++
++    it('does not pass include paths as -I arguments', function () {
++        const args = Config.configToArgs({
++            environment: {},
++            include_paths: ['/path1', '/path2'],
++        }, [], {});
++        expect(args.join(' ')).not.toMatch(/-I/);
++    });
++});
++
++describe('Manipulating the environment', function () {
++    it('sets environment variables in the launcher', function () {
++        const launcher = Config.prepareLauncher({
++            environment: {
++                'MY_VARIABLE': 'my_value',
++            },
++        });
++        expect(launcher.getenv('MY_VARIABLE')).toEqual('my_value');
++    });
++
++    it('unsets environment variables with null values', function () {
++        const launcher = Config.prepareLauncher({
++            environment: {
++                'MY_VARIABLE': null,
++            },
++        });
++        expect(launcher.getenv('MY_VARIABLE')).toBeNull();
++    });
++
++    it('adds one search path', function () {
++        const launcher = Config.prepareLauncher({include_paths: '/a'});
++        expect(launcher.getenv('GJS_PATH')).toEqual('/a');
++    });
++
++    it('adds multiple search paths in the right order', function () {
++        const launcher = Config.prepareLauncher({include_paths: ['/a', '/b']});
++        expect(launcher.getenv('GJS_PATH')).toEqual('/a:/b');
++    });
++
++    it('adds search paths with a lower priority than existing search paths', function () {
++        const oldPath = GLib.getenv('GJS_PATH');
++        GLib.setenv('GJS_PATH', '/a:/b', /* overwrite = */ true);
++        const launcher = Config.prepareLauncher({include_paths: ['/c', '/d']});
++        expect(launcher.getenv('GJS_PATH')).toEqual('/a:/b:/c:/d');
++        if (oldPath)
++            GLib.setenv('GJS_PATH', oldPath, /* overwrite = */ true);
++        else
++            GLib.unsetenv('GJS_PATH');
++    });
++});
++
++describe('Manipulating the launcher command line', function () {
++    let args;
++
++    beforeEach(function () {
++        args = ['jasmine-runner', '--verbose', 'foo.js'];
++    });
++
++    it('executes jasmine-runner with a different interpreter binary', function () {
++        args = Config.wrapArgs(args, {
++            interpreter: '/path/to/custom/gjs',
++        });
++        expect(args).toEqual(['/path/to/custom/gjs', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++
++    it('allows adding arguments to the interpreter', function () {
++        args = Config.wrapArgs(args, {
++            interpreter: 'gjs -d',
++        });
++        expect(args).toEqual(['gjs', '-d', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++
++    it('executes jasmine-runner with a different interpreter binary from the command line', function () {
++        args = Config.wrapArgs(args, {}, {
++            interpreter: '/path/to/custom/gjs',
++        });
++        expect(args).toEqual(['/path/to/custom/gjs', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++
++    it('gives the interpreter specified on the command line priority', function () {
++        args = Config.wrapArgs(args, {
++            interpreter: '/path/to/other/gjs',
++        }, {
++            interpreter: '/path/to/custom/gjs',
++        });
++        expect(args).toEqual(['/path/to/custom/gjs', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++
++    it('executes jasmine-runner with a debugger', function () {
++        args = Config.wrapArgs(args, {}, {
++            debug: 'gdb --args',
++        });
++        expect(args).toEqual(['gdb', '--args', 'gjs', '-m', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++
++    it('does not pass the gjs interpreter to the debugger if a custom one is configured', function () {
++        args = Config.wrapArgs(args, {
++            interpreter: '/path/to/custom/gjs',
++        }, {
++            debug: 'lldb --',
++        });
++        expect(args).toEqual(['lldb', '--', '/path/to/custom/gjs', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++
++    it('does not pass the gjs interpreter to the debugger if a custom one is given on the command line', function () {
++        args = Config.wrapArgs(args, {}, {
++            debug: 'lldb --',
++            interpreter: '/path/to/custom/gjs',
++        });
++        expect(args).toEqual(['lldb', '--', '/path/to/custom/gjs', 'jasmine-runner', '--verbose', 'foo.js']);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..56a824f6f15fb57c2126a7bd7a8c6fe4920dab3a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,118 @@@
++import * as ConsoleReporter from '../src/consoleReporter.js';
++
++describe('Console reporter base class', function () {
++    let reporter, timerSpies;
++    const jasmineCorePath = 'path/to/jasmine/core/jasmine.js';
++
++    beforeEach(function () {
++        timerSpies = {};
++        const timerSpy = id => {
++            timerSpies[id] = jasmine.createSpyObj('timer', ['start', 'elapsed']);
++            return timerSpies[id];
++        };
++        reporter = new ConsoleReporter.ConsoleReporter({
++            timerFactory: timerSpy,
++            jasmineCorePath,
++        });
++    });
++
++    it('can be instantiated', function () {
++        reporter = new ConsoleReporter.ConsoleReporter();
++    });
++
++    it('starts the main timer when Jasmine starts', function () {
++        reporter.jasmineStarted();
++        expect(timerSpies['main'].start).toHaveBeenCalled();
++    });
++
++    it('purges Jasmine internals from stack traces', function () {
++        const fakeStack = [
++            `foo${jasmineCorePath}`,
++            `bar ${jasmineCorePath}`,
++            'line of useful stack trace',
++            `baz ${jasmineCorePath}`,
++        ].join('\n');
++        const stackTrace = reporter.filterStack(fakeStack);
++        expect(stackTrace).toMatch('line of useful stack trace');
++        expect(stackTrace).not.toMatch(jasmineCorePath);
++    });
++
++    describe('started signal', function () {
++        beforeEach(function () {
++            reporter = new ConsoleReporter.ConsoleReporter();
++        });
++
++        it('is emitted when the suite starts', function (done) {
++            reporter.connect('started', () => done());
++            reporter.jasmineStarted();
++        });
++    });
++
++    describe('complete signal', function () {
++        beforeEach(function () {
++            reporter = new ConsoleReporter.ConsoleReporter();
++            reporter.jasmineStarted();
++        });
++
++        it('is emitted with true when the suite is done', function (done) {
++            reporter.connect('complete', (_, success) => {
++                expect(success).toBeTruthy();
++                done();
++            });
++            reporter.jasmineDone();
++        });
++
++        it('is emitted with false if there are spec failures', function (done) {
++            reporter.connect('complete', (_, success) => {
++                expect(success).toBeFalsy();
++                done();
++            });
++            reporter.specDone({status: 'failed', failedExpectations: []});
++            reporter.jasmineDone();
++        });
++
++        it('is emitted with false if there are suite failures', function (done) {
++            reporter.connect('complete', (_, success) => {
++                expect(success).toBeFalsy();
++                done();
++            });
++            reporter.specDone({status: 'passed'});
++            reporter.suiteDone({failedExpectations: [{message: 'bananas'}]});
++            reporter.jasmineDone();
++        });
++    });
++
++    it('times individual suites', function () {
++        const suiteInfo = {id: 'foo'};
++        reporter.suiteStarted(suiteInfo);
++        expect(timerSpies['suite:foo'].start).toHaveBeenCalled();
++
++        timerSpies['suite:foo'].elapsed.and.returnValue(800);
++        reporter.suiteDone(suiteInfo);
++        expect(suiteInfo.time).toBe(800);
++    });
++
++    it('times individual specs', function () {
++        const specInfo = {
++            id: 'foo',
++            status: 'passed',
++        };
++        reporter.specStarted(specInfo);
++        expect(timerSpies['spec:foo'].start).toHaveBeenCalled();
++
++        timerSpies['spec:foo'].elapsed.and.returnValue(800);
++        reporter.specDone(specInfo);
++        expect(specInfo.time).toBe(800);
++    });
++
++    it('starts a timer', function () {
++        reporter.startTimer('foobar');
++        expect(timerSpies['foobar'].start).toHaveBeenCalled();
++    });
++
++    it('gets the elapsed time from a timer', function () {
++        reporter.startTimer('foobar');
++        timerSpies['foobar'].elapsed.and.returnValue(500);
++        expect(reporter.elapsedTime('foobar')).toBe(500);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ca14fabf806688bc1b329165e62ac6945b543fcf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,172 @@@
++import * as ConsoleReporter from '../src/consoleReporter.js';
++
++describe('Default console reporter', function () {
++    let out, reporter, timerSpies;
++
++    beforeEach(function () {
++        out = (function () {
++            let output = '';
++            return {
++                print(str) {
++                    output += str;
++                },
++                getOutput() {
++                    return output;
++                },
++                clear() {
++                    output = '';
++                },
++            };
++        })();
++
++        timerSpies = {};
++        const timerSpy = id => {
++            timerSpies[id] = jasmine.createSpyObj('timer', ['start', 'elapsed']);
++            return timerSpies[id];
++        };
++
++        reporter = new ConsoleReporter.DefaultReporter({
++            print: out.print,
++            show_colors: false,
++            timerFactory: timerSpy,
++        });
++    });
++
++    it('reports that the suite has started to the console', function () {
++        reporter.jasmineStarted();
++        expect(out.getOutput()).toEqual('Started\n');
++    });
++
++    it('reports a passing spec as a dot', function () {
++        reporter.specDone({status: 'passed'});
++        expect(out.getOutput()).toEqual('.');
++    });
++
++    it('does not report a disabled spec', function () {
++        reporter.specDone({status: 'disabled'});
++        expect(out.getOutput()).toEqual('');
++    });
++
++    it('reports a failing spec as an "F"', function () {
++        reporter.specDone({status: 'failed'});
++        expect(out.getOutput()).toEqual('F');
++    });
++
++    it('reports a pending spec as a "*"', function () {
++        reporter.specDone({status: 'pending'});
++        expect(out.getOutput()).toEqual('*');
++    });
++
++    it('alerts user if there are no specs', function () {
++        reporter.jasmineStarted();
++        out.clear();
++        reporter.jasmineDone();
++        expect(out.getOutput()).toMatch(/No specs found/);
++    });
++
++    it('reports a summary when done (singular spec)', function () {
++        reporter.jasmineStarted();
++        reporter.specStarted({});
++        reporter.specDone({status: 'passed'});
++
++        timerSpies['main'].elapsed.and.returnValue(1000);
++
++        out.clear();
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1 spec, 0 failed/);
++        expect(out.getOutput()).not.toMatch(/0 pending/);
++        expect(out.getOutput()).toMatch('Finished in 1 s\n');
++    });
++
++    it('reports a summary when done (pluralized specs)', function () {
++        reporter.jasmineStarted();
++        reporter.specStarted({});
++        reporter.specDone({status: 'passed'});
++        reporter.specStarted({});
++        reporter.specDone({status: 'pending'});
++        reporter.specStarted({});
++        reporter.specDone({
++            status: 'failed',
++            description: 'with a failing spec',
++            fullName: 'A suite with a failing spec',
++            failedExpectations: [{
++                passed: false,
++                message: 'Expected true to be false.',
++                expected: false,
++                actual: true,
++                stack: 'fakeStack\nfakeStack',
++            }],
++        });
++
++        out.clear();
++
++        timerSpies['main'].elapsed.and.returnValue(100);
++
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/3 specs, 1 failed, 1 pending/);
++        expect(out.getOutput()).toMatch('Finished in 0.1 s\n');
++    });
++
++    it('reports a summary when done that includes the failed spec number before the full name of a failing spec', function () {
++        reporter.jasmineStarted();
++        reporter.specDone({status: 'passed'});
++        reporter.specDone({
++            status: 'failed',
++            description: 'with a failing spec',
++            fullName: 'A suite with a failing spec',
++            failedExpectations: [{
++                passed: false,
++                message: 'Expected true to be false.',
++                expected: false,
++                actual: true,
++                stack: 'fakeStack\nfakeStack',
++            }],
++        });
++
++        out.clear();
++
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1\) A suite with a failing spec/);
++    });
++
++    describe('with color', function () {
++        beforeEach(function () {
++            reporter = new ConsoleReporter.DefaultReporter({
++                print: out.print,
++                showColors: true,
++            });
++        });
++
++        it('reports that the suite has started to the console', function () {
++            reporter.jasmineStarted();
++            expect(out.getOutput()).toEqual('Started\n');
++        });
++
++        it('reports a passing spec as a dot', function () {
++            reporter.specDone({status: 'passed'});
++            expect(out.getOutput()).toEqual('\x1B[32m.\x1B[0m');
++        });
++
++        it('does not report a disabled spec', function () {
++            reporter.specDone({status: 'disabled'});
++            expect(out.getOutput()).toEqual('');
++        });
++
++        it('reports a failing spec as an "F"', function () {
++            reporter.specDone({status: 'failed'});
++            expect(out.getOutput()).toEqual('\x1B[31mF\x1B[0m');
++        });
++    });
++
++    it('displays all afterAll exceptions', function () {
++        reporter.suiteDone({failedExpectations: [{message: 'After All Exception'}]});
++        reporter.suiteDone({failedExpectations: [{message: 'Some Other Exception'}]});
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/After All Exception/);
++        expect(out.getOutput()).toMatch(/Some Other Exception/);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f4c0ce09b0c33b66444ba925cdef5b68bdf95166
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++{
++    "include_paths": "include",
++    "spec_files": "someSpec.js"
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4f4305c9ece8f2cf819605276bfa4698579a6e30
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++/* exported importedFunction */
++
++function importedFunction() {
++    return true;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..644ac6378c8640417ea1278a9ebd2d31bdc8b6bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++describe('A spec that should not be loaded', function () {
++    it('is not loaded', function () {
++        fail('Spec was loaded when it should not be');
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644 (file)
--- /dev/null
--- /dev/null
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..88c6fe8c2ff88c9a6308b663e25b5b5fffb259d3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++{
++    "a": "b",
++    "c": "d"
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644 (file)
--- /dev/null
--- /dev/null
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644 (file)
--- /dev/null
--- /dev/null
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fecccbb5006e260bd28e463e959762ce5f817486
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++{
++    "include_paths": ".",
++    "spec_files": "someSpec.js"
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a680d88f01a205e039cb3db5cd8c3ff0a2e9b166
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++describe('A suite', function () {});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6fce0ddc75363483b77dbf81db9355d3e7133577
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++throw new Error('Catch this error to ensure this file is loaded');
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644 (file)
--- /dev/null
--- /dev/null
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..676e58ba37e5b9b7716b036d6dab3f654e6c0b6b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++lett foo = 4;
++describe('SyntaxError suite', function () {});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f860cf111d8b925c6c66e0ed996bcfdcd36a0c1c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++/* eslint no-restricted-globals: off */
++
++// This is a test of focused suites and specs with the fdescribe() and fit()
++// functions. It's taken from Jasmine's documentation suite:
++//   http://jasmine.github.io/2.2/focused_specs.html
++
++// By definition, this suite will disable all other suites that are run during
++// the same invocation of Jasmine -- so it is skipped by default. To run this
++// test anyway, run it explicitly with "jasmine
++// test/focusedSpecIntegrationTest.js". During "make check" it is still run,
++// since make runs the spec files one by one and so this suite won't interfere
++// with any other suites.
++
++describe('Focused specs', function () {
++    fit('is focused and will run', function () {
++        expect(true).toBeTruthy();
++    });
++
++    it('is not focused and will not run', function () {
++        expect(true).toBeFalsy();
++    });
++
++    fdescribe('focused describe', function () {
++        it('will run', function () {
++            expect(true).toBeTruthy();
++        });
++
++        it('will also run', function () {
++            expect(true).toBeTruthy();
++        });
++    });
++
++    fdescribe('another focused describe', function () {
++        fit('is focused and will run', function () {
++            expect(true).toBeTruthy();
++        });
++
++        it('is not focused and will not run', function () {
++            expect(true).toBeFalsy();
++        });
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f75fa65c66b2786a9f9099c901983bc4607b2499
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++const Utils = imports.utils;
++
++describe('Jasmine importer', function () {
++    it('hides Jasmine modules from the test code', function () {
++        expect(Object.keys(Utils)).not.toContain('indenter');
++    });
++
++    it("lets test code import modules named the same as Jasmine's", function () {
++        expect(Utils.add).toBeDefined();
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fd7de3c76f58bae8567e5c82b895a5b3f590e3df
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,191 @@@
++import Gio from 'gi://Gio';
++import GLib from 'gi://GLib';
++
++import * as JasmineBoot from '../src/jasmineBoot.js';
++
++const [testFile] = GLib.filename_from_uri(import.meta.url);
++const testDir = GLib.path_get_dirname(testFile);
++
++const customMatchers = {
++    toMatchAllFiles() {
++        return {
++            compare(actual, expected) {
++                const result = {
++                    message: `Expected ${JSON.stringify(actual)} `,
++                };
++                if (actual.length !== expected.length) {
++                    result.pass = false;
++                    result.message += `to match ${expected.length} ${
++                        expected.length === 1 ? 'file' : 'files'
++                    }, but it contained ${actual.length}`;
++                    return result;
++                }
++
++                let unexpectedFile;
++                result.pass = actual.every(path => {
++                    const actualFile = Gio.File.new_for_path(path);
++                    const retval = expected.some(expectedPath => {
++                        const expectedFile = Gio.File.new_for_path(expectedPath);
++                        return actualFile.equal(expectedFile);
++                    });
++                    if (!retval)
++                        unexpectedFile = path;
++                    return retval;
++                });
++                if (result.pass) {
++                    result.message += `not to match a list of files ${
++                        expected}, but it did.`;
++                } else if (unexpectedFile) {
++                    result.message += `to match a list of files ${expected
++                    }, but it contained ${unexpectedFile}`;
++                } else {
++                    result.message += `to match the list of files ${expected
++                    }, but it did not: ${actual}`;
++                }
++                return result;
++            },
++        };
++    },
++};
++
++describe('Jasmine boot', function () {
++    let testJasmine;
++
++    beforeEach(function () {
++        const bootedJasmine = {
++            getEnv: jasmine.createSpy('getEnv').and.returnValue({
++                addReporter: jasmine.createSpy('addReporter'),
++                execute: jasmine.createSpy('execute'),
++                configure: jasmine.createSpy('configure'),
++            }),
++            Timer: jasmine.createSpy('Timer'),
++            Expectation: {
++                addMatchers: jasmine.createSpy('addMatchers'),
++            },
++        };
++
++        const fakeJasmineRequireObj = {
++            core: jasmine.createSpy('core').and.returnValue(bootedJasmine),
++            interface: jasmine.createSpy('interface'),
++        };
++
++        const fakeJasmineCore = {
++            getJasmineRequireObj() {
++                return fakeJasmineRequireObj;
++            },
++            __file__: 'fake/jasmine/path/jasmine.js',
++        };
++
++        testJasmine = new JasmineBoot.Jasmine({jasmineCore: fakeJasmineCore});
++
++        jasmine.addMatchers(customMatchers);
++    });
++
++    it('adds a nonexistent spec file', function () {
++        expect(testJasmine.specFiles).toEqual([]);
++        testJasmine.addSpecFiles([`${testDir}/non/existent/file.js`]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/non/existent/file.js`,
++        ]);
++    });
++
++    it('adds a real spec file', function () {
++        expect(testJasmine.specFiles).toEqual([]);
++        testJasmine.addSpecFiles([`${testDir}/fixtures/someSpec.js`]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/fixtures/someSpec.js`,
++        ]);
++    });
++
++    it('adds more than one spec file', function () {
++        expect(testJasmine.specFiles).toEqual([]);
++        testJasmine.addSpecFiles([
++            `${testDir}/fixtures/someSpec.js`,
++            `${testDir}/fixtures/otherSpec.js`,
++        ]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/fixtures/someSpec.js`,
++            `${testDir}/fixtures/otherSpec.js`,
++        ]);
++    });
++
++    it('adds a whole directory of spec files', function () {
++        expect(testJasmine.specFiles).toEqual([]);
++        testJasmine.addSpecFiles([`${testDir}/fixtures`]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/fixtures/include/module.js`,
++            `${testDir}/fixtures/include/spec.js`,
++            `${testDir}/fixtures/otherSpec.js`,
++            `${testDir}/fixtures/path1/test.js`,
++            `${testDir}/fixtures/path2/test.js`,
++            `${testDir}/fixtures/someSpec.js`,
++            `${testDir}/fixtures/syntaxErrorSpec.js`,
++        ]);
++        expect(testJasmine.specFiles.every(path => path.indexOf('notASpec.txt') === -1)).toBe(true);
++    });
++
++    it('adds spec files in different directories with the same name', function () {
++        testJasmine.addSpecFiles([
++            `${testDir}/fixtures/path1`,
++            `${testDir}/fixtures/path2`,
++        ]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/fixtures/path1/test.js`,
++            `${testDir}/fixtures/path2/test.js`,
++        ]);
++    });
++
++    it('respects excluded files', function () {
++        testJasmine.exclusions = ['otherSpec.js', 'syntaxErrorSpec.js'];
++        testJasmine.addSpecFiles([`${testDir}/fixtures`]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/fixtures/include/module.js`,
++            `${testDir}/fixtures/include/spec.js`,
++            `${testDir}/fixtures/someSpec.js`,
++            `${testDir}/fixtures/path1/test.js`,
++            `${testDir}/fixtures/path2/test.js`,
++        ]);
++    });
++
++    it('matches at the end of the containing path', function () {
++        testJasmine.exclusions = ['test/fixtures'];
++        testJasmine.addSpecFiles([`${testDir}/fixtures`]);
++        expect(testJasmine.specFiles).toMatchAllFiles([
++            `${testDir}/fixtures/include/module.js`,
++            `${testDir}/fixtures/include/spec.js`,
++            `${testDir}/fixtures/path1/test.js`,
++            `${testDir}/fixtures/path2/test.js`,
++        ]);
++    });
++
++    it('can handle globs in excluded files', function () {
++        testJasmine.exclusions = ['*.js'];
++        testJasmine.addSpecFiles([`${testDir}/fixtures`]);
++        expect(testJasmine.specFiles).toMatchAllFiles([]);
++    });
++
++    it('adds the Jasmine path when adding a reporter', function () {
++        const fakeReporter = {};
++        testJasmine.addReporter(fakeReporter);
++        expect(fakeReporter.jasmine_core_path).toMatch('fake/jasmine/path');
++    });
++
++    it('imports spec files in different directories with the same name', function () {
++        testJasmine.addSpecFiles([
++            `${testDir}/fixtures/path1`,
++            `${testDir}/fixtures/path2`,
++        ]);
++        expectAsync(testJasmine.loadSpecs()).toBeRejectedWithError(Error,
++            'Catch this error to ensure this file is loaded');
++    });
++
++    it('does not bail out altogether if one of the specs has a syntax error', function () {
++        testJasmine.addSpecFiles([`${testDir}/fixtures/syntaxErrorSpec.js`]);
++        expect(() => testJasmine.loadSpecs()).not.toThrow();
++    });
++
++    it('does not bail out altogether if one of the specs does not exist', function () {
++        testJasmine.addSpecFiles(['non/existent/file.js']);
++        expect(() => testJasmine.loadSpecs()).not.toThrow();
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..835ab404040b06455fe613793dbcce6d6c6e918e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1012 @@@
++// This suite is Jasmine's documentation suite, exercising all of Jasmine's
++// functionality to make sure that the GJS test runner has hooked everything up
++// correctly. It's taken from the following pages:
++//    https://jasmine.github.io/2.3/introduction.html
++//    https://jasmine.github.io/2.3/custom_equality.html
++//    https://jasmine.github.io/2.3/custom_matcher.html
++//
++// Note: the "long asynchronous specs" suite near the bottom takes 9 seconds to
++// run. It is marked pending by default. To run this suite anyway, define an
++// environment variable RUN_THOROUGH_TESTS=yes.
++
++/* global setInterval, setTimeout */
++
++import GLib from 'gi://GLib';
++
++describe('Jasmine integration test', function () {
++    describe("A suite", function () {
++        it("contains spec with an expectation", function () {
++            expect(true).toBe(true);
++        });
++    });
++
++    describe("A suite is just a function", function () {
++        var a;
++
++        it("and so is a spec", function () {
++            a = true;
++
++            expect(a).toBe(true);
++        });
++    });
++
++    describe("The 'toBe' matcher compares with ===", function () {
++        it("and has a positive case", function () {
++            expect(true).toBe(true);
++        });
++
++        it("and can have a negative case", function () {
++            expect(false).not.toBe(true);
++        });
++    });
++
++    describe("Included matchers:", function () {
++        it("The 'toBe' matcher compares with ===", function () {
++            var a = 12;
++            var b = a;
++
++            expect(a).toBe(b);
++            expect(a).not.toBe(null);
++        });
++
++        describe("The 'toEqual' matcher", function () {
++            it("works for simple literals and variables", function () {
++                var a = 12;
++                expect(a).toEqual(12);
++            });
++
++            it("should work for objects", function () {
++                var foo = {
++                    a: 12,
++                    b: 34
++                };
++                var bar = {
++                    a: 12,
++                    b: 34
++                };
++                expect(foo).toEqual(bar);
++            });
++        });
++
++        it("The 'toMatch' matcher is for regular expressions", function () {
++            var message = "foo bar baz";
++
++            expect(message).toMatch(/bar/);
++            expect(message).toMatch("bar");
++            expect(message).not.toMatch(/quux/);
++        });
++
++        it("The 'toBeDefined' matcher compares against `undefined`", function () {
++            var a = {
++                foo: "foo"
++            };
++
++            expect(a.foo).toBeDefined();
++            expect(a.bar).not.toBeDefined();
++        });
++
++        it("The `toBeUndefined` matcher compares against `undefined`", function () {
++            var a = {
++                foo: "foo"
++            };
++
++            expect(a.foo).not.toBeUndefined();
++            expect(a.bar).toBeUndefined();
++        });
++
++        it("The 'toBeNull' matcher compares against null", function () {
++            var a = null;
++            var foo = "foo";
++
++            expect(null).toBeNull();
++            expect(a).toBeNull();
++            expect(foo).not.toBeNull();
++        });
++
++        it("The 'toBeTruthy' matcher is for boolean casting testing", function () {
++            var a, foo = "foo";
++
++            expect(foo).toBeTruthy();
++            expect(a).not.toBeTruthy();
++        });
++
++        it("The 'toBeFalsy' matcher is for boolean casting testing", function () {
++            var a, foo = "foo";
++
++            expect(a).toBeFalsy();
++            expect(foo).not.toBeFalsy();
++        });
++
++        describe("The 'toContain' matcher", function () {
++            it("works for finding an item in an Array", function () {
++                var a = ["foo", "bar", "baz"];
++
++                expect(a).toContain("bar");
++                expect(a).not.toContain("quux");
++            });
++
++            it("also works for finding a substring", function () {
++                var a = "foo bar baz";
++
++                expect(a).toContain("bar");
++                expect(a).not.toContain("quux");
++            });
++        });
++
++        it("The 'toBeLessThan' matcher is for mathematical comparisons", function () {
++            var pi = 3.1415926,
++            e = 2.78;
++
++            expect(e).toBeLessThan(pi);
++            expect(pi).not.toBeLessThan(e);
++        });
++
++        it("The 'toBeGreaterThan' matcher is for mathematical comparisons", function () {
++            var pi = 3.1415926,
++            e = 2.78;
++
++            expect(pi).toBeGreaterThan(e);
++            expect(e).not.toBeGreaterThan(pi);
++        });
++
++        it("The 'toBeCloseTo' matcher is for precision math comparison", function () {
++            var pi = 3.1415926,
++            e = 2.78;
++
++            expect(pi).not.toBeCloseTo(e, 2);
++            expect(pi).toBeCloseTo(e, 0);
++        });
++
++        it("The 'toThrow' matcher is for testing if a function throws an exception", function () {
++            var foo = function () {
++                return 1 + 2;
++            };
++            var bar = function () {
++                return a + 1;
++            };
++            var baz = function () {
++                throw 'what';
++            };
++
++            expect(foo).not.toThrow();
++            expect(bar).toThrow();
++            expect(baz).toThrow('what');
++        });
++
++        it("The 'toThrowError' matcher is for testing a specific thrown exception", function () {
++            var foo = function () {
++                throw new TypeError("foo bar baz");
++            };
++
++            expect(foo).toThrowError("foo bar baz");
++            expect(foo).toThrowError(/bar/);
++            expect(foo).toThrowError(TypeError);
++            expect(foo).toThrowError(TypeError, "foo bar baz");
++        });
++    });
++
++    describe("A spec using the fail function", function () {
++        var foo = function (x, callBack) {
++            if (x) {
++                callBack();
++            }
++        };
++
++        it("should not call the callBack", function () {
++            foo(false, function () {
++                fail("Callback has been called");
++            });
++        });
++    });
++
++    describe("A spec", function () {
++        it("is just a function, so it can contain any code", function () {
++            var foo = 0;
++            foo += 1;
++
++            expect(foo).toEqual(1);
++        });
++
++        it("can have more than one expectation", function () {
++            var foo = 0;
++            foo += 1;
++
++            expect(foo).toEqual(1);
++            expect(true).toEqual(true);
++        });
++    });
++
++    describe("A spec using beforeEach and afterEach", function () {
++        var foo = 0;
++
++        beforeEach(function () {
++            foo += 1;
++        });
++
++        afterEach(function () {
++            foo = 0;
++        });
++
++        it("is just a function, so it can contain any code", function () {
++            expect(foo).toEqual(1);
++        });
++
++        it("can have more than one expectation", function () {
++            expect(foo).toEqual(1);
++            expect(true).toEqual(true);
++        });
++    });
++
++    describe("A spec using beforeAll and afterAll", function () {
++        var foo;
++
++        beforeAll(function () {
++            foo = 1;
++        });
++
++        afterAll(function () {
++            foo = 0;
++        });
++
++        it("sets the initial value of foo before specs run", function () {
++            expect(foo).toEqual(1);
++            foo += 1;
++        });
++
++        it("does not reset foo between specs", function () {
++            expect(foo).toEqual(2);
++        });
++    });
++
++    describe("A spec", function () {
++        beforeEach(function () {
++            this.foo = 0;
++        });
++
++        it("can use the `this` to share state", function () {
++            expect(this.foo).toEqual(0);
++            this.bar = "test pollution?";
++        });
++
++        it("prevents test pollution by having an empty `this` created for the next spec", function () {
++            expect(this.foo).toEqual(0);
++            expect(this.bar).toBe(undefined);
++        });
++    });
++
++    describe("A spec", function () {
++        var foo;
++
++        beforeEach(function () {
++            foo = 0;
++            foo += 1;
++        });
++
++        afterEach(function () {
++            foo = 0;
++        });
++
++        it("is just a function, so it can contain any code", function () {
++            expect(foo).toEqual(1);
++        });
++
++        it("can have more than one expectation", function () {
++            expect(foo).toEqual(1);
++            expect(true).toEqual(true);
++        });
++
++        describe("nested inside a second describe", function () {
++            var bar;
++
++            beforeEach(function () {
++                bar = 1;
++            });
++
++            it("can reference both scopes as needed", function () {
++                expect(foo).toEqual(bar);
++            });
++        });
++    });
++
++    xdescribe("A spec", function () {
++        var foo;
++
++        beforeEach(function () {
++            foo = 0;
++            foo += 1;
++        });
++
++        it("is just a function, so it can contain any code", function () {
++            expect(foo).toEqual(1);
++        });
++    });
++
++    describe("Pending specs", function () {
++        xit("can be declared 'xit'", function () {
++            expect(true).toBe(false);
++        });
++
++        it("can be declared with 'it' but without a function");
++
++        it("can be declared by calling 'pending' in the spec body", function () {
++            expect(true).toBe(false);
++            pending('this is why it is pending');
++        });
++    });
++
++    describe("A spy", function () {
++        var foo, bar = null;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                }
++            };
++
++            spyOn(foo, 'setBar');
++
++            foo.setBar(123);
++            foo.setBar(456, 'another param');
++        });
++
++        it("tracks that the spy was called", function () {
++            expect(foo.setBar).toHaveBeenCalled();
++        });
++
++        it("tracks that the spy was called x times", function () {
++            expect(foo.setBar).toHaveBeenCalledTimes(2);
++        });
++
++        it("tracks all the arguments of its calls", function () {
++            expect(foo.setBar).toHaveBeenCalledWith(123);
++            expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
++        });
++
++        it("stops all execution on a function", function () {
++            expect(bar).toBeNull();
++        });
++    });
++
++    describe("A spy, when configured to call through", function () {
++        var foo, bar, fetchedBar;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                },
++                getBar: function () {
++                    return bar;
++                }
++            };
++
++            spyOn(foo, 'getBar').and.callThrough();
++
++            foo.setBar(123);
++            fetchedBar = foo.getBar();
++        });
++
++        it("tracks that the spy was called", function () {
++            expect(foo.getBar).toHaveBeenCalled();
++        });
++
++        it("should not affect other functions", function () {
++            expect(bar).toEqual(123);
++        });
++
++        it("when called returns the requested value", function () {
++            expect(fetchedBar).toEqual(123);
++        });
++    });
++
++    describe("A spy, when configured to fake a return value", function () {
++        var foo, bar, fetchedBar;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                },
++                getBar: function () {
++                    return bar;
++                }
++            };
++
++            spyOn(foo, "getBar").and.returnValue(745);
++
++            foo.setBar(123);
++            fetchedBar = foo.getBar();
++        });
++
++        it("tracks that the spy was called", function () {
++            expect(foo.getBar).toHaveBeenCalled();
++        });
++
++        it("should not affect other functions", function () {
++            expect(bar).toEqual(123);
++        });
++
++        it("when called returns the requested value", function () {
++            expect(fetchedBar).toEqual(745);
++        });
++    });
++
++    describe("A spy, when configured to fake a series of return values", function () {
++        var foo, bar;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function(value) {
++                    bar = value;
++                },
++                getBar: function () {
++                    return bar;
++                }
++            };
++
++            spyOn(foo, "getBar").and.returnValues("fetched first", "fetched second");
++
++            foo.setBar(123);
++        });
++
++        it("tracks that the spy was called", function () {
++            foo.getBar(123);
++            expect(foo.getBar).toHaveBeenCalled();
++        });
++
++        it("should not affect other functions", function () {
++            expect(bar).toEqual(123);
++        });
++
++        it("when called multiple times returns the requested values in order", function () {
++            expect(foo.getBar()).toEqual("fetched first");
++            expect(foo.getBar()).toEqual("fetched second");
++            expect(foo.getBar()).toBeUndefined();
++        });
++    });
++
++    describe("A spy, when configured with an alternate implementation", function () {
++        var foo, bar, fetchedBar;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                },
++                getBar: function () {
++                    return bar;
++                }
++            };
++
++            spyOn(foo, "getBar").and.callFake(function (args, can, be, received) {
++                return 1001;
++            });
++
++            foo.setBar(123);
++            fetchedBar = foo.getBar();
++        });
++
++        it("tracks that the spy was called", function () {
++            expect(foo.getBar).toHaveBeenCalled();
++        });
++
++        it("should not affect other functions", function () {
++            expect(bar).toEqual(123);
++        });
++
++        it("when called returns the requested value", function () {
++            expect(fetchedBar).toEqual(1001);
++        });
++    });
++
++    describe("A spy, when configured to throw an error", function () {
++        var foo, bar;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                }
++            };
++
++            spyOn(foo, "setBar").and.throwError("quux");
++        });
++
++        it("throws the value", function () {
++            expect(function () {
++                foo.setBar(123);
++            }).toThrowError("quux");
++        });
++    });
++
++    describe("A spy", function () {
++        var foo, bar = null;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                }
++            };
++
++            spyOn(foo, 'setBar').and.callThrough();
++        });
++
++        it("can call through and then stub in the same spec", function () {
++            foo.setBar(123);
++            expect(bar).toEqual(123);
++
++            foo.setBar.and.stub();
++            bar = null;
++
++            foo.setBar(123);
++            expect(bar).toBe(null);
++        });
++    });
++
++    describe("A spy", function () {
++        var foo, bar = null;
++
++        beforeEach(function () {
++            foo = {
++                setBar: function (value) {
++                    bar = value;
++                }
++            };
++
++            spyOn(foo, 'setBar');
++        });
++
++        it("tracks if it was called at all", function () {
++            expect(foo.setBar.calls.any()).toEqual(false);
++
++            foo.setBar();
++
++            expect(foo.setBar.calls.any()).toEqual(true);
++        });
++
++        it("tracks the number of times it was called", function () {
++            expect(foo.setBar.calls.count()).toEqual(0);
++
++            foo.setBar();
++            foo.setBar();
++
++            expect(foo.setBar.calls.count()).toEqual(2);
++        });
++
++        it("tracks the arguments of each call", function () {
++            foo.setBar(123);
++            foo.setBar(456, "baz");
++
++            expect(foo.setBar.calls.argsFor(0)).toEqual([123]);
++            expect(foo.setBar.calls.argsFor(1)).toEqual([456, "baz"]);
++        });
++
++        it("tracks the arguments of all calls", function () {
++            foo.setBar(123);
++            foo.setBar(456, "baz");
++
++            expect(foo.setBar.calls.allArgs()).toEqual([[123],[456, "baz"]]);
++        });
++
++        it("can provide the context and arguments to all calls", function () {
++            foo.setBar(123);
++
++            expect(foo.setBar.calls.all()).toEqual([jasmine.objectContaining({object: foo, args: [123], returnValue: undefined})]);
++        });
++
++        it("has a shortcut to the most recent call", function () {
++            foo.setBar(123);
++            foo.setBar(456, "baz");
++
++            expect(foo.setBar.calls.mostRecent()).toEqual(jasmine.objectContaining({object: foo, args: [456, "baz"], returnValue: undefined}));
++        });
++
++        it("has a shortcut to the first call", function () {
++            foo.setBar(123);
++            foo.setBar(456, "baz");
++
++            expect(foo.setBar.calls.first()).toEqual(jasmine.objectContaining({object: foo, args: [123], returnValue: undefined}));
++        });
++
++        it("tracks the context", function () {
++            var spy = jasmine.createSpy('spy');
++            var baz = {
++                fn: spy
++            };
++            var quux = {
++                fn: spy
++            };
++            baz.fn(123);
++            quux.fn(456);
++
++            expect(spy.calls.first().object).toBe(baz);
++            expect(spy.calls.mostRecent().object).toBe(quux);
++        });
++
++        it("can be reset", function () {
++            foo.setBar(123);
++            foo.setBar(456, "baz");
++
++            expect(foo.setBar.calls.any()).toBe(true);
++
++            foo.setBar.calls.reset();
++
++            expect(foo.setBar.calls.any()).toBe(false);
++        });
++    });
++
++    describe("A spy, when created manually", function () {
++        var whatAmI;
++
++        beforeEach(function () {
++            whatAmI = jasmine.createSpy('whatAmI');
++
++            whatAmI("I", "am", "a", "spy");
++        });
++
++        it("is named, which helps in error reporting", function () {
++            expect(whatAmI.and.identity).toEqual('whatAmI');
++        });
++
++        it("tracks that the spy was called", function () {
++            expect(whatAmI).toHaveBeenCalled();
++        });
++
++        it("tracks its number of calls", function () {
++            expect(whatAmI.calls.count()).toEqual(1);
++        });
++
++        it("tracks all the arguments of its calls", function () {
++            expect(whatAmI).toHaveBeenCalledWith("I", "am", "a", "spy");
++        });
++
++        it("allows access to the most recent call", function () {
++            expect(whatAmI.calls.mostRecent().args[0]).toEqual("I");
++        });
++    });
++
++    describe("Multiple spies, when created manually", function () {
++        var tape;
++
++        beforeEach(function () {
++            tape = jasmine.createSpyObj('tape', ['play', 'pause', 'stop', 'rewind']);
++
++            tape.play();
++            tape.pause();
++            tape.rewind(0);
++        });
++
++        it("creates spies for each requested function", function () {
++            expect(tape.play).toBeDefined();
++            expect(tape.pause).toBeDefined();
++            expect(tape.stop).toBeDefined();
++            expect(tape.rewind).toBeDefined();
++        });
++
++        it("tracks that the spies were called", function () {
++            expect(tape.play).toHaveBeenCalled();
++            expect(tape.pause).toHaveBeenCalled();
++            expect(tape.rewind).toHaveBeenCalled();
++            expect(tape.stop).not.toHaveBeenCalled();
++        });
++
++        it("tracks all the arguments of its calls", function () {
++            expect(tape.rewind).toHaveBeenCalledWith(0);
++        });
++    });
++
++    describe("jasmine.any", function () {
++        it("matches any value", function () {
++            expect({}).toEqual(jasmine.any(Object));
++            expect(12).toEqual(jasmine.any(Number));
++        });
++
++        describe("when used with a spy", function () {
++            it("is useful for comparing arguments", function () {
++                var foo = jasmine.createSpy('foo');
++                foo(12, function () {
++                    return true;
++                });
++
++                expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function));
++            });
++        });
++    });
++
++    describe("jasmine.anything", function () {
++        it("matches anything", function () {
++            expect(1).toEqual(jasmine.anything());
++        });
++
++        describe("when used with a spy", function () {
++            it("is useful when the argument can be ignored", function () {
++                var foo = jasmine.createSpy('foo');
++                foo(12, function () {
++                    return false;
++                });
++
++                expect(foo).toHaveBeenCalledWith(12, jasmine.anything());
++            });
++        });
++    });
++
++    describe("jasmine.objectContaining", function () {
++        var foo;
++
++        beforeEach(function () {
++            foo = {
++                a: 1,
++                b: 2,
++                bar: "baz"
++            };
++        });
++
++        it("matches objects with the expect key/value pairs", function () {
++            expect(foo).toEqual(jasmine.objectContaining({
++                bar: "baz"
++            }));
++            expect(foo).not.toEqual(jasmine.objectContaining({
++                c: 37
++            }));
++        });
++
++        describe("when used with a spy", function () {
++            it("is useful for comparing arguments", function () {
++                var callback = jasmine.createSpy('callback');
++
++                callback({
++                    bar: "baz"
++                });
++
++                expect(callback).toHaveBeenCalledWith(jasmine.objectContaining({
++                    bar: "baz"
++                }));
++                expect(callback).not.toHaveBeenCalledWith(jasmine.objectContaining({
++                    c: 37
++                }));
++            });
++        });
++    });
++
++    describe("jasmine.arrayContaining", function () {
++        var foo;
++
++        beforeEach(function () {
++            foo = [1, 2, 3, 4];
++        });
++
++        it("matches arrays with some of the values", function () {
++            expect(foo).toEqual(jasmine.arrayContaining([3, 1]));
++            expect(foo).not.toEqual(jasmine.arrayContaining([6]));
++        });
++
++        describe("when used with a spy", function () {
++            it("is useful when comparing arguments", function () {
++                var callback = jasmine.createSpy('callback');
++
++                callback([1, 2, 3, 4]);
++
++                expect(callback).toHaveBeenCalledWith(jasmine.arrayContaining([4, 2, 3]));
++                expect(callback).not.toHaveBeenCalledWith(jasmine.arrayContaining([5, 2]));
++            });
++        });
++    });
++
++    describe('jasmine.stringMatching', function () {
++        it("matches as a regexp", function () {
++            expect({foo: 'bar'}).toEqual({foo: jasmine.stringMatching(/^bar$/)});
++            expect({foo: 'foobarbaz'}).toEqual({foo: jasmine.stringMatching('bar')});
++        });
++
++        describe("when used with a spy", function () {
++            it("is useful for comparing arguments", function () {
++                var callback = jasmine.createSpy('callback');
++
++                callback('foobarbaz');
++
++                expect(callback).toHaveBeenCalledWith(jasmine.stringMatching('bar'));
++                expect(callback).not.toHaveBeenCalledWith(jasmine.stringMatching(/^bar$/));
++            });
++        });
++    });
++
++    describe("custom asymmetry", function () {
++        var tester = {
++            asymmetricMatch: function (actual) {
++                var secondValue = actual.split(',')[1];
++                return secondValue === 'bar';
++            }
++        };
++
++        it("dives in deep", function () {
++            expect("foo,bar,baz,quux").toEqual(tester);
++        });
++
++        describe("when used with a spy", function () {
++            it("is useful for comparing arguments", function () {
++                var callback = jasmine.createSpy('callback');
++
++                callback('foo,bar,baz');
++
++                expect(callback).toHaveBeenCalledWith(tester);
++            });
++        });
++    });
++
++    describe("Manually ticking the Jasmine Clock", function () {
++        var timerCallback;
++
++        beforeEach(function () {
++            timerCallback = jasmine.createSpy("timerCallback");
++            jasmine.clock().install();
++        });
++
++        afterEach(function () {
++            jasmine.clock().uninstall();
++        });
++
++        it("causes a timeout to be called synchronously", function () {
++            setTimeout(function () {
++                timerCallback();
++            }, 100);
++
++            expect(timerCallback).not.toHaveBeenCalled();
++
++            jasmine.clock().tick(101);
++
++            expect(timerCallback).toHaveBeenCalled();
++        });
++
++        it("causes an interval to be called synchronously", function () {
++            setInterval(function () {
++                timerCallback();
++            }, 100);
++
++            expect(timerCallback).not.toHaveBeenCalled();
++
++            jasmine.clock().tick(101);
++            expect(timerCallback.calls.count()).toEqual(1);
++
++            jasmine.clock().tick(50);
++            expect(timerCallback.calls.count()).toEqual(1);
++
++            jasmine.clock().tick(50);
++            expect(timerCallback.calls.count()).toEqual(2);
++        });
++
++        describe("Mocking the Date object", function () {
++            it("mocks the Date object and sets it to a given time", function () {
++                var baseTime = new Date(2013, 9, 23);
++                // If you do not provide a base time to `mockDate` it will use the current date.
++                jasmine.clock().mockDate(baseTime);
++
++                jasmine.clock().tick(50);
++                expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
++            });
++        });
++    });
++
++    describe("Asynchronous specs", function () {
++        var value;
++
++        beforeEach(function (done) {
++            setTimeout(function () {
++                value = 0;
++                done();
++            }, 1);
++        });
++
++        it("should support async execution of test preparation and expectations", function (done) {
++            value++;
++            expect(value).toBeGreaterThan(0);
++            done();
++        });
++
++        describe("long asynchronous specs", function () {
++            beforeEach(function (done) {
++                done();
++            }, 1000);
++
++            if (GLib.getenv('RUN_THOROUGH_TESTS') === 'yes') {
++                it("takes a long time", function (done) {
++                    setTimeout(function () {
++                        done();
++                    }, 9000);
++                }, 10000);
++            }
++
++            afterEach(function (done) {
++                done();
++            }, 1000);
++        });
++
++        describe("A spec using done.fail", function() {
++            var foo = function(x, callBack1, callBack2) {
++                if (x) {
++                    setTimeout(callBack1, 0);
++                } else {
++                    setTimeout(callBack2, 0);
++                }
++            };
++
++            it("should not call the second callBack", function(done) {
++                foo(true,
++                    done,
++                    function() {
++                        done.fail("Second callback has been called");
++                    }
++                );
++            });
++        });
++    });
++
++    describe("custom equality", function () {
++        var myCustomEquality = function (first, second) {
++            if (typeof first == "string" && typeof second == "string") {
++                return first[0] == second[1];
++            }
++        };
++
++        beforeEach(function () {
++            jasmine.addCustomEqualityTester(myCustomEquality);
++        });
++
++        it("should be custom equal", function () {
++            expect("abc").toEqual("aaa");
++        });
++
++        it("should be custom not equal", function () {
++            expect("abc").not.toEqual("abc");
++        });
++    });
++
++    var customMatchers = {
++        toBeGoofy: function (util, customEqualityTesters) {
++            return {
++                compare: function (actual, expected) {
++                    if (expected === undefined) {
++                        expected = '';
++                    }
++
++                    var result = {};
++
++                    result.pass = util.equals(actual.hyuk, "gawrsh" + expected, customEqualityTesters);
++
++                    if (result.pass) {
++                        result.message = "Expected " + actual + " not to be quite so goofy";
++                    } else {
++                        result.message = "Expected " + actual + " to be goofy, but it was not very goofy";
++                    }
++
++                    return result;
++                }
++            };
++        }
++    };
++
++    describe("Custom matcher: 'toBeGoofy'", function () {
++        beforeEach(function () {
++            jasmine.addMatchers(customMatchers);
++        });
++
++        it("is available on an expectation", function () {
++            expect({
++                hyuk: 'gawrsh'
++            }).toBeGoofy();
++        });
++
++        it("can take an 'expected' parameter", function () {
++            expect({
++                hyuk: 'gawrsh is fun'
++            }).toBeGoofy(' is fun');
++        });
++
++        it("can be negated", function () {
++            expect({
++                hyuk: 'this is fun'
++            }).not.toBeGoofy();
++        });
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6c4061eaae0b217d8ab16800919b276f98064f21
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,470 @@@
++import GLib from 'gi://GLib';
++
++import * as JUnitReporter from '../src/junitReporter.js';
++import * as XMLWriter from '../src/xmlWriter.js';
++
++const SUITE_INFO = {
++    id: 'foo',
++    description: 'A suite',
++    fullName: 'A suite',
++    failedExpectations: [],
++    status: 'finished',
++};
++const NESTED_SUITE_INFO = {
++    id: 'baz',
++    description: 'nested',
++    fullName: 'A suite nested',
++    failedExpectations: [],
++    status: 'finished',
++};
++const FAILED_SUITE_INFO = {
++    id: 'cheers',
++    description: 'A failing suite',
++    fullName: 'A failing suite',
++    failedExpectations: [{
++        matcherName: '',
++        message: 'Some error',
++        stack: 'file.js:113\nfile.js:72\nfile.js:17\n',
++    }],
++    status: 'failed',
++};
++const PASSING_SPEC_INFO = {
++    id: 'bar',
++    description: 'passes a test',
++    fullName: 'A suite passes a test',
++    failedExpectations: [],
++    passedExpectations: [
++        {
++            matcherName: 'toBe',
++            message: 'Expected true to be true',
++        },
++        {
++            matcherName: 'toContain',
++            message: 'Expected [1] to contain 1',
++        },
++    ],
++    status: 'passed',
++};
++const NESTED_PASSING_SPEC_INFO = {
++    id: 'boz',
++    description: 'passes a test',
++    fullName: 'A suite nested passes a test',
++    failedExpectations: [],
++    passedExpectations: [],
++    status: 'passed',
++};
++const PENDING_SPEC_INFO = {
++    id: 'skip',
++    description: 'skips a test',
++    fullName: 'A suite skips a test',
++    failedExpectations: [],
++    passedExpectations: [],
++    status: 'pending',
++};
++const FAILING_SPEC_INFO = {
++    id: 'bad',
++    description: 'fails a test',
++    fullName: 'A suite fails a test',
++    failedExpectations: [{
++        matcherName: 'toBe',
++        message: 'Expected true to be false',
++        stack: 'file.js:113\nfile.js:72\nfile.js:17\n',
++    }],
++    passedExpectations: [],
++    status: 'failed',
++};
++const ERROR_SPEC_INFO = {
++    id: 'bug',
++    description: 'has a bug in a test',
++    fullName: 'A suite has a bug in a test',
++    failedExpectations: [
++        {
++            matcherName: '',
++            message: 'TypeError: foo is not a function',
++            stack: 'file.js:113\nfile.js:72\nfile.js:17\n',
++        },
++        {
++            matcherName: '',
++            message: 'Some other unknown error',
++            stack: 'file.js:113\nfile.js:72\nfile.js:17\n',
++        },
++    ],
++    passedExpectations: [],
++    status: 'failed',
++};
++const DISABLED_SPEC_INFO = {
++    id: 'wut',
++    description: 'disables a test',
++    fullName: 'A suite disables a test',
++    failedExpectations: [],
++    passedExpectations: [],
++    status: 'disabled',
++};
++
++describe('The JUnit reporter', function () {
++    let out, reporter, timerSpies;
++
++    beforeEach(function () {
++        // Override the XML outputting function to output JSON instead. This is
++        // for ease of verifying the output. XML is inconvenient to parse in the
++        // DOM-less GJS. Any regressions in the XML output should not be tested
++        // here, but instead should be covered in xmlWriterSpec.js.
++        spyOn(XMLWriter.Node.prototype, 'toString').and.callFake(function () {
++            return JSON.stringify(this);
++        });
++
++        out = (function () {
++            let output = '';
++            return {
++                print(str) {
++                    output += str;
++                },
++                getOutput() {
++                    return output;
++                },
++                clear() {
++                    output = '';
++                },
++            };
++        })();
++
++        timerSpies = {};
++        const timerSpy = id => {
++            timerSpies[id] = jasmine.createSpyObj('timer', ['start', 'elapsed']);
++            return timerSpies[id];
++        };
++
++        reporter = new JUnitReporter.JUnitReporter({
++            print: out.print,
++            timerFactory: timerSpy,
++        });
++        reporter.jasmineStarted();
++    });
++
++    function runSpec(specInfo) {
++        reporter.specStarted(specInfo);
++        reporter.specDone(specInfo);
++    }
++
++    function runSuite(suiteInfo, specs) {
++        reporter.suiteStarted(suiteInfo);
++        specs.forEach(runSpec);
++        reporter.suiteDone(suiteInfo);
++    }
++
++    // Find the <testsuite> element with the given ID inside the <testsuites>
++    // element given by tree. This is necessary because other elements may be
++    // present such as, <properties>, so we cannot rely on the element with ID 0
++    // being the first child of <testsuites>.
++    function findSuite(tree, id) {
++        for (let index = 0; index < tree.children.length; index++) {
++            const child = tree.children[index];
++            if (child.name === 'testsuite' && child.attrs['id'] === id)
++                return child;
++        }
++        return undefined;
++    }
++
++    // For XML builder reasons, the report is only output at the end of all the
++    // test suites. Therefore all tests must call jasmineDone().
++
++    it('outputs a JUnit report', function () {
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        expect(tree.name).toBe('testsuites');
++    });
++
++    it('reports all required elements of a test suite', function () {
++        runSuite(SUITE_INFO, []);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.name).toBe('testsuite');
++        expect(testsuite.attrs['name']).toBe('A suite');
++        expect(testsuite.attrs['tests']).toBe(0);
++    });
++
++    it('reports all required elements of a test case element', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        const [{name, attrs}] = testsuite.children;
++        expect(name).toBe('testcase');
++        expect(attrs['name']).toBe('passes a test');
++        expect(attrs['classname']).toBe('A suite');
++    });
++
++    it('reports a pending spec as skipped', function () {
++        runSuite(SUITE_INFO, [PENDING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        const [{children}] = testsuite.children;
++        expect(children[0].name).toBe('skipped');
++    });
++
++    describe('given a spec with a failed expectation', function () {
++        let failure;
++
++        beforeEach(function () {
++            runSuite(SUITE_INFO, [FAILING_SPEC_INFO]);
++            reporter.jasmineDone();
++
++            const tree = JSON.parse(out.getOutput());
++            const testsuite = findSuite(tree, 0);
++            [failure] = testsuite.children[0].children;
++        });
++
++        it('reports it as failed', function () {
++            expect(failure.name).toBe('failure');
++        });
++
++        it('reports the matcher name as the failure type', function () {
++            if (!failure.attrs.hasOwnProperty('type'))
++                pending();
++            expect(failure.attrs['type']).toBe('toBe');
++        });
++
++        it('reports the expectation message', function () {
++            if (!failure.attrs.hasOwnProperty('message'))
++                pending();
++            expect(failure.attrs['message']).toBe('Expected true to be false');
++        });
++
++        it('reports the stack trace', function () {
++            expect(failure.text).toBe('file.js:113\nfile.js:72\nfile.js:17\n');
++        });
++    });
++
++    describe('given a spec with an uncaught exception', function () {
++        let error1, error2;
++
++        beforeEach(function () {
++            runSuite(SUITE_INFO, [ERROR_SPEC_INFO]);
++            reporter.jasmineDone();
++
++            const tree = JSON.parse(out.getOutput());
++            const testsuite = findSuite(tree, 0);
++            [error1, error2] = testsuite.children[0].children;
++        });
++
++        it('reports it as errored', function () {
++            expect(error1.name).toBe('error');
++            expect(error2.name).toBe('error');
++        });
++
++        it('reports the exception class as the failure type', function () {
++            expect(error1.attrs['type']).toBe('TypeError');
++        });
++
++        it('picks a default type if the exception class is not known', function () {
++            expect(error2.attrs['type']).toBe('Error');
++        });
++
++        it('reports the error message', function () {
++            expect(error1.attrs['message']).toBe('TypeError: foo is not a function');
++            expect(error2.attrs['message']).toBe('Some other unknown error');
++        });
++
++        it('reports the stack trace', function () {
++            expect(error1.text).toBe('file.js:113\nfile.js:72\nfile.js:17\n');
++            expect(error2.text).toBe('file.js:113\nfile.js:72\nfile.js:17\n');
++        });
++    });
++
++    it('does not report a disabled spec', function () {
++        runSuite(SUITE_INFO, [DISABLED_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.children.length).toBe(0);
++    });
++
++    it('gives each suite an increasing ID number', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO]);
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO]);
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        tree.children.filter(child => child.name === 'testsuite')
++        .forEach((child, index) => {
++            expect(child.attrs['id']).toBe(index);
++        });
++    });
++
++    it('times all suites together', function () {
++        timerSpies['main'].elapsed.and.returnValue(1200);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        expect(tree.attrs['time']).toBeCloseTo(1.2, 4);
++    });
++
++    it('times individual suites', function () {
++        reporter.suiteStarted(SUITE_INFO);
++        timerSpies[`suite:${SUITE_INFO.id}`].elapsed.and.returnValue(100);
++        reporter.suiteDone(SUITE_INFO);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.attrs['time']).toBeCloseTo(0.1, 4);
++    });
++
++    it('times individual specs', function () {
++        reporter.suiteStarted(SUITE_INFO);
++        reporter.specStarted(PASSING_SPEC_INFO);
++        timerSpies[`spec:${PASSING_SPEC_INFO.id}`].elapsed.and.returnValue(100);
++        reporter.specDone(PASSING_SPEC_INFO);
++        reporter.suiteDone(SUITE_INFO);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        const [{attrs}] = testsuite.children;
++        expect(attrs['time']).toBeCloseTo(0.1, 4);
++    });
++
++    it('counts all tests in a suite', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO, PASSING_SPEC_INFO, PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.attrs['tests']).toBe(3);
++    });
++
++    it('counts disabled tests in a suite', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO, DISABLED_SPEC_INFO, PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.attrs['disabled']).toBe(1);
++    });
++
++    it('counts errored tests in a suite', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO, ERROR_SPEC_INFO, PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.attrs['errors']).toBe(1);
++    });
++
++    it('counts failed tests in a suite', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO, FAILING_SPEC_INFO, PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.attrs['failures']).toBe(1);
++    });
++
++    it('counts skipped tests in a suite', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO, PENDING_SPEC_INFO, PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.attrs['skipped']).toBe(1);
++    });
++
++    it('timestamps a suite', function () {
++        runSuite(SUITE_INFO, []);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(() => Date.parse(testsuite.attrs['timestamp'])).not.toThrow();
++    });
++
++    it('flattens nested suites', function () {
++        reporter.suiteStarted(SUITE_INFO);
++        [PASSING_SPEC_INFO, PASSING_SPEC_INFO].forEach(runSpec);
++        reporter.suiteStarted(NESTED_SUITE_INFO);
++        [NESTED_PASSING_SPEC_INFO, NESTED_PASSING_SPEC_INFO].forEach(runSpec);
++        reporter.suiteDone(NESTED_SUITE_INFO);
++        runSpec(PASSING_SPEC_INFO);
++        reporter.suiteDone(SUITE_INFO);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const suite1 = findSuite(tree, 0);
++        const suite2 = findSuite(tree, 1);
++        expect(suite1.attrs['tests']).toBe(3);
++        expect(suite2.attrs['tests']).toBe(2);
++    });
++
++    it('reports exceptions in afterAll() as errors in a separate suite', function () {
++        runSuite(FAILED_SUITE_INFO, [PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const afterAllSuite = findSuite(tree, 1);
++        expect(afterAllSuite.attrs['tests']).toBe(1);
++        expect(afterAllSuite.attrs['errors']).toBe(1);
++    });
++
++    it('reports an error in afterAll() as a test case', function () {
++        runSuite(FAILED_SUITE_INFO, [PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const afterAllSuite = findSuite(tree, 1);
++        expect(afterAllSuite.children[0]).toEqual(jasmine.objectContaining({
++            name: 'testcase',
++            attrs: jasmine.any(Object),
++            children: [jasmine.objectContaining({
++                name: 'error',
++                attrs: jasmine.objectContaining({
++                    message: 'Some error',
++                    type: 'Error',
++                }),
++                text: 'file.js:113\nfile.js:72\nfile.js:17\n',
++            })],
++        }));
++    });
++
++    it('adds the environment in a <properties> element', function () {
++        GLib.setenv('JASMINE_TESTS_BOGUS_VARIABLE', 'surprise', true);
++        reporter.jasmineStarted(); // restart
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const [properties] = tree.children.filter(child => child.name === 'properties');
++        expect(properties.children).toContain(jasmine.objectContaining({
++            name: 'property',
++            attrs: {
++                name: 'JASMINE_TESTS_BOGUS_VARIABLE',
++                value: 'surprise',
++            },
++        }));
++    });
++
++    it('reports the total number of assertions', function () {
++        runSuite(SUITE_INFO, [PASSING_SPEC_INFO, ERROR_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const testsuite = findSuite(tree, 0);
++        expect(testsuite.children[0].attrs['assertions']).toBe(2);
++        expect(testsuite.children[1].attrs['assertions']).toBe(2);
++    });
++
++    it('reports the total number of assertions in an afterAll() suite', function () {
++        runSuite(FAILED_SUITE_INFO, [PASSING_SPEC_INFO]);
++        reporter.jasmineDone();
++
++        const tree = JSON.parse(out.getOutput());
++        const afterAllSuite = findSuite(tree, 1);
++        expect(afterAllSuite.children[0].attrs['assertions']).toBe(1);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..25fbf3258dcf288c3fe6dff02c56f2db15e4a580
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,47 @@@
++// FIXME: the argument parser should be refactored into something more general
++// so that the ARGS object in options.js isn't hardcoded.
++
++import * as Options from '../src/options.js';
++
++describe('Argument parser', function () {
++    it('stores the given value for a "store" argument', function () {
++        const [files, namespace] = Options.parseOptions(['--junit', 'file.txt']);
++        expect(files).toEqual([]);
++        expect(namespace['junit']).toEqual('file.txt');
++    });
++
++    it('stores the value from "const" for a "store" argument if none given', function () {
++        const [files, namespace] = Options.parseOptions(['--junit']);
++        expect(files).toEqual([]);
++        expect(namespace['junit']).toEqual('report.xml');
++    });
++
++    it('stores values in the order they are given on the command line', function () {
++        const [, namespace] = Options.parseOptions(['--no-color', '--color']);
++        expect(namespace['color']).toBe(true);
++    });
++
++    it('stores the given value for an "append" argument', function () {
++        const [, namespace] = Options.parseOptions(['--exclude', 'file.js']);
++        expect(namespace['exclude']).toEqual(['file.js']);
++    });
++
++    it('stores multiple values for an "append" argument appearing multiple times', function () {
++        const [, namespace] = Options.parseOptions([
++            '--exclude', 'file.js',
++            '--exclude', 'file2.js',
++        ]);
++        expect(namespace['exclude']).toEqual(['file.js', 'file2.js']);
++    });
++
++    it('does not modify the list of arguments passed in', function () {
++        const args = ['arg1', 'arg2', 'arg3'];
++        Options.parseOptions(args);
++        expect(args.length).toBe(3);
++    });
++
++    it('does not treat a short option as a file', function () {
++        const [files] = Options.parseOptions(['-c', 'file.js']);
++        expect(files).toEqual(['file.js']);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ea90afc996b5ee3c84c3b8e550f755908be68f28
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,251 @@@
++import * as TapReporter from '../src/tapReporter.js';
++
++describe('The TAP reporter', function () {
++    let out, reporter;
++
++    beforeEach(function () {
++        out = (function () {
++            let output = '';
++            return {
++                print(str) {
++                    output += str;
++                },
++                getOutput() {
++                    return output;
++                },
++                clear() {
++                    output = '';
++                },
++            };
++        })();
++
++        reporter = new TapReporter.TapReporter({
++            print: out.print,
++        });
++    });
++
++    it('outputs a test plan', function () {
++        reporter.jasmineStarted({totalSpecsDefined: 1});
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'passed',
++        });
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1../);
++    });
++
++    it('includes the total number of specs in the test plan', function () {
++        reporter.jasmineStarted({totalSpecsDefined: 2});
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'passed',
++        });
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'bar',
++            status: 'passed',
++        });
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1..2/);
++    });
++
++    it('outputs an empty test plan if there were no specs', function () {
++        reporter.jasmineStarted({totalSpecsDefined: 0});
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1..0/);
++    });
++
++    it('outputs a line starting with "ok" for a passing spec', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'passed',
++        });
++        expect(out.getOutput()).toMatch(/^ok/);
++    });
++
++    it('outputs a line starting with "not ok" for a failing spec', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'failed',
++        });
++        expect(out.getOutput()).toMatch(/^not ok/);
++    });
++
++    it('outputs an "ok" line plus a skip directive for a pending spec', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'pending',
++        });
++        expect(out.getOutput()).toMatch(/^ok/);
++        expect(out.getOutput()).toMatch(/# skip/i);
++    });
++
++    it('reports the reason for a pending spec, if given', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'pending',
++            pendingReason: 'because I said so',
++        });
++        expect(out.getOutput()).toMatch('because I said so');
++    });
++
++    it('outputs an "ok" line plus a skip directive for a disabled spec', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'disabled',
++        });
++        expect(out.getOutput()).toMatch(/^ok/);
++        expect(out.getOutput()).toMatch(/# skip/i);
++    });
++
++    it('outputs a sequence number after the result', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'foo',
++            status: 'passed',
++        });
++        expect(out.getOutput()).toMatch(/^ok 1/);
++        out.clear();
++        reporter.specStarted({});
++        reporter.specDone({
++            fullName: 'bar',
++            status: 'failed',
++        });
++        expect(out.getOutput()).toMatch(/^not ok 2/);
++    });
++
++    it('outputs the name of the spec on the test line', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            status: 'passed',
++            fullName: 'A passing spec',
++        });
++        expect(out.getOutput()).toMatch(/^ok.*A passing spec/);
++        out.clear();
++        reporter.specStarted({});
++        reporter.specDone({
++            status: 'failed',
++            fullName: 'A failing spec',
++        });
++        expect(out.getOutput()).toMatch(/^not ok.*A failing spec/);
++    });
++
++    it('does not let the name start with a digit', function () {
++        reporter.specStarted({});
++        reporter.specDone({
++            status: 'passed',
++            fullName: '3 careless programmers wrote this',
++        });
++        expect(out.getOutput()).toMatch(/^ok 1/);
++        expect(out.getOutput()).not.toMatch(/^ok 1\s*[0-9]+/);
++    });
++
++    describe('on failure', function () {
++        beforeEach(function () {
++            reporter.specStarted({});
++            out.clear();
++            reporter.specDone({
++                fullName: 'foo',
++                status: 'failed',
++                failedExpectations: [
++                    {
++                        message: 'Expected the earth and the sky.',
++                        stack: 'line 1\nline 2\nline 3',
++                    },
++                    {
++                        message: 'Expectations exceeded.',
++                        stack: 'line 4\nline 5',
++                    },
++                ],
++            });
++        });
++
++        it('outputs messages on the test line', function () {
++            const output = out.getOutput();
++            const [testLine] = output.split('\n');
++            expect(testLine).toMatch(/^not ok.*Expected the earth and the sky\./);
++            expect(testLine).toMatch(/^not ok.*Expectations exceeded\./);
++        });
++
++        it('outputs messages and stack traces as diagnostic lines', function () {
++            const diagnostics = out.getOutput().split('\n').slice(1);
++            expect(diagnostics).toMatch(/^#.*Expected the earth and the sky\./m);
++            expect(diagnostics).toMatch(/^#.*Expectations exceeded\./m);
++            expect(diagnostics).toMatch(/^#.*line 1/m);
++            expect(diagnostics).toMatch(/^#.*line 2/m);
++            expect(diagnostics).toMatch(/^#.*line 3/m);
++            expect(diagnostics).toMatch(/^#.*line 4/m);
++            expect(diagnostics).toMatch(/^#.*line 5/m);
++        });
++    });
++
++    describe('on failure with newlines', function () {
++        beforeEach(function () {
++            reporter.specStarted({});
++            out.clear();
++            reporter.specDone({
++                fullName: 'foo',
++                status: 'failed',
++                failedExpectations: [{
++                    message: 'A message\non two lines',
++                    stack: '',
++                }],
++            });
++        });
++
++        it('prints no newlines on the test line', function () {
++            const [testLine] = out.getOutput().split('\n');
++            expect(testLine).toMatch(/^not ok.*A message.*on two lines/);
++        });
++
++        it('prints no newlines in the diagnostics', function () {
++            const diagnostics = out.getOutput().split('\n').slice(1);
++            expect(diagnostics).not.toMatch(/^[^#]/);
++        });
++    });
++
++    it('reports suites starting as diagnostic lines', function () {
++        reporter.suiteStarted({
++            fullName: 'A suite',
++        });
++        expect(out.getOutput()).toMatch(/^#.*A suite/);
++    });
++
++    it('reports suites finishing successfully as diagnostic lines', function () {
++        reporter.suiteDone({
++            status: 'passed',
++            fullName: 'A suite',
++            failedExpectations: [],
++        });
++        expect(out.getOutput()).toMatch(/^#.*A suite/);
++    });
++
++    it('reports suites with failing specs as diagnostic lines', function () {
++        reporter.suiteDone({
++            status: 'failed',
++            fullName: 'A suite',
++            failedExpectations: [],
++        });
++        expect(out.getOutput()).toMatch(/^#.*A suite/);
++    });
++
++    it('reports failures in afterAll as an extra failure', function () {
++        reporter.suiteDone({
++            status: 'failed',
++            fullName: 'A suite',
++            failedExpectations: [{message: 'An afterAll exception'}],
++        });
++        reporter.jasmineDone();
++        expect(out.getOutput()).toMatch(/^not ok.*An afterAll exception/m);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..28756e88828e0fcccb4037aa6644f584e615bf22
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++import * as Timer from '../src/timer.js';
++
++describe('The default timer', function () {
++    it('stops timing when elapsed() is called', function () {
++        const timer = Timer.createDefaultTimer();
++        timer.start();
++        expect(timer.elapsed()).toEqual(timer.elapsed());
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..39b4d1ed6234dd558abd384ec1d450b982699fa3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++function add(a, b) {
++    return a + b;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3d84b5185cedf045a54456122cc6a3edddb39f42
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++import {indenter} from '../src/utils.js';
++
++describe('Indent', function () {
++    it('prepends spaces to a string', function () {
++        expect(indenter.indent('foo', 4)).toEqual('    foo');
++    });
++
++    it('prepends spaces to each line in a string', function () {
++        expect(indenter.indent('a\nb\nc', 4)).toEqual('    a\n    b\n    c');
++    });
++
++    it('does not indent an extra blank line at the end of the string', function () {
++        expect(indenter.indent('a\nb\n', 4)).toEqual('    a\n    b\n');
++    });
++
++    it('handles zero spaces', function () {
++        expect(indenter.indent('foo', 0)).toEqual('foo');
++        expect(indenter.indent('a\nb\nc', 0)).toEqual('a\nb\nc');
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..91415d4d04be3932a5db0298056cdc92da8c459a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,307 @@@
++import * as VerboseReporter from '../src/verboseReporter.js';
++import {indenter} from '../src/utils.js';
++
++describe('Verbose console reporter', function () {
++    let out, reporter, timerSpy, timerSpies;
++
++    beforeEach(function () {
++        out = (function () {
++            let output = '';
++            return {
++                print(str) {
++                    output += str;
++                },
++                getOutput() {
++                    return output;
++                },
++                clear() {
++                    output = '';
++                },
++            };
++        })();
++
++        timerSpies = {};
++        timerSpy = id => {
++            timerSpies[id] = jasmine.createSpyObj('timer', ['start', 'elapsed']);
++            return timerSpies[id];
++        };
++
++        reporter = new VerboseReporter.VerboseReporter({
++            print: out.print,
++            show_colors: false,
++            timerFactory: timerSpy,
++        });
++
++        // disable indentation for test purposes
++        spyOn(indenter, 'indent').and.callFake(str => str);
++    });
++
++    it('reports that the suite has started to the console', function () {
++        reporter.jasmineStarted();
++        expect(out.getOutput()).toEqual('Started\n\n');
++    });
++
++    it('reports a passing spec with a checkmark', function () {
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            status: 'passed',
++            description: 'A passing spec',
++        });
++        expect(out.getOutput()).toEqual('✓ A passing spec\n');
++    });
++
++    it('reports a disabled spec with an "x"', function () {
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            status: 'disabled',
++            description: 'A disabled spec',
++        });
++        expect(out.getOutput()).toEqual('x A disabled spec\n');
++    });
++
++    it('reports a failing spec with a number', function () {
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            status: 'failed',
++            description: 'A failing spec',
++        });
++        expect(out.getOutput()).toEqual('1) A failing spec\n');
++    });
++
++    it('reports a failing spec with the number of that failure in sequence', function () {
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            status: 'failed',
++            description: 'A failing spec',
++        });
++        out.clear();
++        reporter.specStarted({id: 'bar'});
++        reporter.specDone({
++            id: 'bar',
++            status: 'failed',
++            description: 'Another failing spec',
++        });
++        expect(out.getOutput()).toEqual('2) Another failing spec\n');
++    });
++
++    it('reports a pending spec as a dash', function () {
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            status: 'pending',
++            description: 'A pending spec',
++        });
++        expect(out.getOutput()).toEqual('- A pending spec\n');
++    });
++
++    it('reports a summary when done', function () {
++        reporter.jasmineStarted();
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            description: 'A spec',
++            status: 'passed',
++        });
++        reporter.specStarted({id: 'bar'});
++        reporter.specDone({
++            id: 'bar',
++            description: 'A spec',
++            status: 'pending',
++        });
++        reporter.specStarted({id: 'baz'});
++        reporter.specDone({
++            id: 'baz',
++            status: 'failed',
++            description: 'with a failing spec',
++            fullName: 'A suite with a failing spec',
++            failedExpectations: [{
++                passed: false,
++                message: 'Expected true to be false.',
++                expected: false,
++                actual: true,
++                stack: 'fakeStack\nfakeStack',
++            }],
++        });
++
++        out.clear();
++
++        timerSpies['main'].elapsed.and.returnValue(100);
++
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1 passing \(0.1 s\)/);
++        expect(out.getOutput()).toMatch(/1 pending/);
++        expect(out.getOutput()).toMatch(/1 failing/);
++    });
++
++    it('reports a summary when done even if there are no specs', function () {
++        reporter.jasmineStarted();
++        timerSpies['main'].elapsed.and.returnValue(100);
++        out.clear();
++        reporter.jasmineDone();
++        expect(out.getOutput()).toMatch(/0 passing \(0.1 s\)/);
++    });
++
++    it('reports a summary when done that includes the failed spec number before the full name of a failing spec', function () {
++        reporter.jasmineStarted();
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            description: 'A spec',
++            status: 'passed',
++        });
++        reporter.specStarted({id: 'bar'});
++        reporter.specDone({
++            id: 'bar',
++            status: 'failed',
++            description: 'with a failing spec',
++            fullName: 'A suite with a failing spec',
++            failedExpectations: [{
++                passed: false,
++                message: 'Expected true to be false.',
++                expected: false,
++                actual: true,
++                stack: 'fakeStack\nfakeStack',
++            }],
++        });
++
++        out.clear();
++
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/1\) A suite with a failing spec/);
++    });
++
++    it('prints a warning when a spec takes over 40 ms', function () {
++        reporter.specStarted({id: 'foo'});
++        timerSpies['spec:foo'].elapsed.and.returnValue(50);
++        reporter.specDone({
++            id: 'foo',
++            description: 'A spec',
++            status: 'passed',
++        });
++
++        expect(out.getOutput()).toMatch('(50 ms)');
++    });
++
++    it('prints the reason for a pending spec', function () {
++        reporter.specStarted({id: 'foo'});
++        reporter.specDone({
++            id: 'foo',
++            status: 'pending',
++            description: 'a pending spec',
++            pendingReason: 'it was not ready',
++        });
++        expect(out.getOutput()).toMatch('(it was not ready)');
++    });
++
++    describe('with color', function () {
++        beforeEach(function () {
++            reporter = new VerboseReporter.VerboseReporter({
++                print: out.print,
++                showColors: true,
++                timerFactory: timerSpy,
++            });
++        });
++
++        it('reports that the suite has started to the console', function () {
++            reporter.jasmineStarted();
++            expect(out.getOutput()).toEqual('Started\n\n');
++        });
++
++        it('reports a passing spec with a checkmark', function () {
++            reporter.specStarted({id: 'foo'});
++            reporter.specDone({
++                id: 'foo',
++                status: 'passed',
++                description: 'A passing spec',
++            });
++            expect(out.getOutput()).toEqual('\x1b[32m✓\x1b[0m A passing spec\n');
++        });
++
++        it('reports a disabled spec with an "x"', function () {
++            reporter.specStarted({id: 'foo'});
++            reporter.specDone({
++                id: 'foo',
++                status: 'disabled',
++                description: 'A disabled spec',
++            });
++            expect(out.getOutput()).toEqual('x A disabled spec\n');
++        });
++
++        it('reports a failing spec with a number', function () {
++            reporter.specStarted({id: 'foo'});
++            reporter.specDone({
++                id: 'foo',
++                status: 'failed',
++                description: 'A failing spec',
++            });
++            expect(out.getOutput()).toEqual('\x1b[31m1)\x1b[0m A failing spec\n');
++        });
++
++        it('reports a disabled suite with "disabled"', function () {
++            reporter.suiteDone({
++                status: 'disabled',
++                description: 'A disabled suite',
++            });
++            expect(out.getOutput()).toEqual('\x1b[33m(disabled)\x1b[0m\n');
++        });
++
++        it('prints a mild warning when a spec takes over 40 ms', function () {
++            reporter.specStarted({id: 'foo'});
++            timerSpies['spec:foo'].elapsed.and.returnValue(50);
++            reporter.specDone({
++                id: 'foo',
++                description: 'A spec',
++                status: 'passed',
++            });
++
++            // eslint-disable-next-line no-control-regex
++            expect(out.getOutput()).toMatch(/\x1b\[33m\(50 ms\)\x1b\[0m/);
++        });
++
++        it('prints a loud warning when a spec takes over 75 ms', function () {
++            reporter.specStarted({id: 'foo'});
++            timerSpies['spec:foo'].elapsed.and.returnValue(80);
++            reporter.specDone({
++                id: 'foo',
++                description: 'A spec',
++                status: 'passed',
++            });
++
++            // eslint-disable-next-line no-control-regex
++            expect(out.getOutput()).toMatch(/\x1b\[31m\(80 ms\)\x1b\[0m/);
++        });
++
++        it('prints a pending reason in yellow', function () {
++            reporter.specStarted({id: 'foo'});
++            reporter.specDone({
++                id: 'foo',
++                status: 'pending',
++                description: 'a pending spec',
++                pendingReason: 'it was not ready',
++            });
++            // eslint-disable-next-line no-control-regex
++            expect(out.getOutput()).toMatch(/\x1b\[33m\(it was not ready\)\x1b\[0m/);
++        });
++    });
++
++    it('displays all afterAll exceptions', function () {
++        reporter.suiteDone({
++            status: 'failed',
++            failedExpectations: [{message: 'After All Exception'}],
++        });
++        reporter.suiteDone({
++            status: 'failed',
++            failedExpectations: [{message: 'Some Other Exception'}],
++        });
++        reporter.jasmineDone();
++
++        expect(out.getOutput()).toMatch(/After All Exception/);
++        expect(out.getOutput()).toMatch(/Some Other Exception/);
++    });
++});
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..de8bd255ae5f3b07da747f90fb0035240b1f4467
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,98 @@@
++import * as XMLWriter from '../src/xmlWriter.js';
++
++describe('XML writer', function () {
++    let node;
++
++    beforeEach(function () {
++        node = new XMLWriter.Node('node');
++    });
++
++    it('prints a doctype declaration', function () {
++        expect(node.toString()).toMatch(/^<\?xml version=(['"])1\.0\1 encoding=(['"])UTF-8\2\?>/);
++    });
++
++    it('prints a single empty node', function () {
++        expect(node.toString()).toMatch('<node/>');
++    });
++
++    it('prints a single node with an attribute', function () {
++        node.attrs = {
++            attr: 'value',
++        };
++        expect(node.toString()).toMatch(/<node attr=(['"])value\1\/>/);
++    });
++
++    it('separates attributes with a space', function () {
++        node.attrs = {
++            attr: 'value',
++            key: 'something',
++        };
++        expect(node.toString()).toMatch(/<node attr=(['"])value\1 key=(['"])something\2\/>/);
++    });
++
++    it('escapes attribute values', function () {
++        node.attrs = {
++            attr: '"<>&\'',
++        };
++        expect(node.toString()).toMatch(/<node attr=(['"])&quot;&lt;&gt;&amp;&apos;\1\/>/);
++    });
++
++    it('prints child nodes', function () {
++        node.children.push(new XMLWriter.Node('child'));
++        expect(node.toString()).toMatch(/<node>\s*<child\/>\s*<\/node>/);
++    });
++
++    it('prints child nodes in order', function () {
++        node.children = [
++            new XMLWriter.Node('child-one'),
++            new XMLWriter.Node('child-two'),
++            new XMLWriter.Node('child-three'),
++        ];
++        expect(node.toString()).toMatch(/<node>\s*<child-one\/>\s*<child-two\/>\s*<child-three\/>\s*<\/node>/);
++    });
++
++    it('prints child nodes indented', function () {
++        node.children.push(new XMLWriter.Node('child'));
++        expect(node.toString()).toMatch('<node>\n  <child/>\n</node>\n');
++    });
++
++    it('prints multiple levels of indentation', function () {
++        const child = new XMLWriter.Node('child');
++        child.children.push(new XMLWriter.Node('descendant'));
++        node.children.push(child);
++        const output = node.toString();
++        expect(output).toMatch('\n<node>\n');
++        expect(output).toMatch('\n  <child>\n');
++        expect(output).toMatch('\n    <descendant/>\n');
++        expect(output).toMatch('\n  </child>\n');
++        expect(output).toMatch('\n</node>\n');
++    });
++
++    it('prints text content', function () {
++        node.text = 'A very fine day';
++        expect(node.toString()).toMatch(/<node>\s*A very fine day\s*<\/node>/);
++    });
++
++    it('prints text content indented', function () {
++        node.text = 'A very fine day';
++        expect(node.toString()).toMatch('\n  A very fine day\n');
++    });
++
++    it('trims text content', function () {
++        node.text = '     \nA very fine day\n     ';
++        expect(node.toString()).toMatch('<node>\n  A very fine day\n</node>');
++    });
++
++    it('escapes text content', function () {
++        node.text = '"<>&\'';
++        expect(node.toString()).toMatch('&quot;&lt;&gt;&amp;&apos;');
++    });
++
++    it('prints child nodes and text content', function () {
++        node.children.push(new XMLWriter.Node('child'));
++        node.text = 'Other content';
++        const output = node.toString();
++        expect(output).toMatch('<child/>');
++        expect(output).toMatch('Other content');
++    });
++});